- Home /
How to get the name of a List from one of its items
So I got two Lists<> of GameObjects and i got a Method i want to pass one of those lists depending on which GameObject made the call to the method. Maybe some code might explain it a little easier:
List<GameObject> playerList1 = new List<GameObject>(4);
List<GameObject> playerList2 = new List<GameObject>(4);
public void SwitchPlayerSelection(List<GameObject> playerList){
foreach(player in playerList){
if(player.isSelected) player.isSelected = false;
}
this.isSelected = true;
}
So if some other script is calling this method when manipulating a playerobject, I want to be able to deselect all playerobjects from the list the calling playerobject belongs to, and just select the one calling it ( this
). But how do I find out, which List it DOES belong to? Here's an example:
//imaginary method GET_LIST_NAME
if(myPlayerObject.needsToBeSelected){
myPlayerObject.SwitchPlayerSelection(myPlayerObject.GET_LIST_NAME())
}
Note that i DO have workarounds for this (like checking both lists with List.Contains()
and then looping through the appropriate one, or just use a Dictionary in the first place. But I'm curious if there is a feature of C#'s Lists (or arrays!!!) that allows me to conclude the list's name from one of its items. Thanks in advance.
yep, but as ImpOfThePerverse mentioned, it's probably impossible. It makes sense that there's no additional meta-data attached to objects in a list after all.
It doesn't sound like that's possible: https://stackoverflow.com/questions/2064139/how-to-find-references-to-an-object-in-c-sharp Any number of lists and reference variables can point to a single object, so they're responsible for keeping track of the reference. The object itself is unaware of what's referencing it.
Your workaround with List.Contains() is probably the way to go.
Answer by QKlon · May 28, 2018 at 01:52 AM
Since any object - even int, float aso. - can become an item of a generic collection, there is no built-in to refer to the list(s), an object is listed in. Actually an object does not even know that it is referenced by a list. (There is only an internal reference counter used by garbage collection.) Further more c# lists do not have a name property like the UnityEngine.Object
class. You have to implement it on your own. As you mentioned, the common 'workaround' is to lookup the possible lists. When using binary tree driven collections, the lookup time is acceptable even on larger numbers of items.
If you want more automatism and easier access, you can derive your own class from a collection of your choice and implement the corrosponding methods to your needs.
Here is a demo. Just copy it into a file 'ListedPlayer.cs', start play mode and read the console output. You can (and should in a productive environment) split it into multiple files.
ListedPlayer.cs
using System.Collections.Generic;
using UnityEngine;
namespace Demo
{
public class ListedPlayer : MonoBehaviour
{
public string Membership
{
get
{
var rel = GetComponent<Relation>();
return rel ? rel.BackRefToList.name : "none";
}
}
}
public class Relation : MonoBehaviour
{
public BackRefItemList BackRefToList { get; private set; }
// nested list class having access to private property
public class BackRefItemList : List<GameObject>
{
public string name;
//list constructors
public BackRefItemList(string name = null)
{
setName(name);
}
public BackRefItemList(IEnumerable<GameObject> collection = null, string name = null) : base(collection)
{
setName(name);
}
public BackRefItemList(int capacity = 0, string name = null) : base(capacity)
{
setName(name);
}
private void setName(string name = null)
{
this.name = null == name ? "unnamed list" : name;
}
public void Add(GameObject gameObject)
{
base.Add(gameObject);
Relation rel = gameObject.GetComponent<Relation>();
if(!rel)
{
rel = gameObject.AddComponent<Relation>();
rel.BackRefToList = this;
return;
}
if(rel.BackRefToList != this)
{
rel.BackRefToList.Remove(gameObject);
rel.BackRefToList = this;
}
}
}
}
public static class Global
{
public static Relation.BackRefItemList PlayerList1 = new Relation.BackRefItemList("Team 1");
public static Relation.BackRefItemList PlayerList2 = new Relation.BackRefItemList("Team 2");
public static GameObject[] players = new GameObject[8];
[RuntimeInitializeOnLoadMethod]
public static void testPlayList()
{
// init
for(var i = 0; i<8; i++)
(i<4 ? PlayerList1 : PlayerList2).Add(players[i] = new GameObject("Player "+i, typeof(ListedPlayer)));
doTestOutputs("initialized player list");
// let 2 players of team 1 join to team 2
PlayerList2.Add(players[0]);
PlayerList2.Add(players[1]);
doTestOutputs("modified teams");
}
public static void doTestOutputs(string header)
{
Debug.Log("<b>"+header+"</b>");
for(var i = 0; i<8; i++)
{
var p = players[i];
Debug.Log("'" + p.name + "' is member of team '" + p.GetComponent<ListedPlayer>().Membership + "':");
}
foreach (var team in new[]{PlayerList1, PlayerList2})
{
Debug.Log("<b>Teammembers '" + team.name + "':</b>");
foreach (var teamPlayer in team)
Debug.Log(teamPlayer.GetComponent<ListedPlayer>().name);
}
}
}
}
Thank you very very much for this detailed and useful answer!
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Reference all objects inside of an Array or List? 2 Answers
A node in a childnode? 1 Answer
Filling array with Scribtable Objects automaticly? 1 Answer
C#: Array question, check value 1 Answer