roguedev
roguedev

Reputation: 195

How to use an index on a variable

I have a list which I currently add items to in the following way:

public GameObject object1 = new GameObject("Example Data");
public GameObject object2 = new GameObject("Example Data");
public GameObject object3 = new GameObject("Example Data");
public GameObject object4 = new GameObject("Example Data");
public GameObject object5 = new GameObject("Example Data");
public GameObject object6 = new GameObject("Example Data");
public GameObject object7 = new GameObject("Example Data");
public GameObject object8 = new GameObject("Example Data");
public GameObject object9 = new GameObject("Example Data");
public GameObject object10 = new GameObject("Example Data");
List<GameObject> Objects = new List<GameObject>();

Objects.Add(object1);
Objects.Add(object2);
Objects.Add(object3);
Objects.Add(object4);
Objects.Add(object5);
Objects.Add(object6);
Objects.Add(object7);
Objects.Add(object8);
Objects.Add(object9);
Objects.Add(object10);

How would I do this in C# using a foreach? I tried something like the following example but I couldn't get it to work:

foreach (var number in Enumerable.Range(1, 10))
{
    Objects.Add("object" + [number]);
}

Upvotes: 0

Views: 104

Answers (4)

John Wu
John Wu

Reputation: 52230

In order to read a private field using a dynamically-generated name, you'll need to write a special function to read it via Reflection. Here is how I would write such a function:

public static object GetFieldValue(this object input, string name)
{
    return input
        .GetType()
        .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
        .ToList()
        .Where(f => f.Name == name)
        .Single()
        .GetValue(input);
}

You can then use it like this:

for (int i = 1; i <= 10; i++)
{
    string fieldName = "object" + i.ToString();
    var o = this.GetFieldValue(fieldName);
    objects.Add(o);
}

That being said, this is not a great idea. In fact, this is a really weird thing to do. The normal way you'd deal with this is to omit the objectX variables completely; just store each instance in the list.

List<GameObject> Objects = new List<GameObject>();
for (int i=0; i<10; i++)
{
    Objects.Add(new GameObject("Example data"));
}

If you need to get one of the instances back out of the list, just reference it by index (although you may have to subtract 1 since it is 0-based):

var object1 = Objects[0];

Another way to deal with it, especially if each of those instances is unique in some way, it to use a dictionary:

Dictionary<string, GameObject> objects = new Dictionary<string, GameObject>();
objects["Player"] = new GameObject("I am a player");
objects["Enemy"] = new GameObject("I am an enemy");
objects["NPC"] = new GameObject("I am a hapless bystander");

Then you can access each of the individual objects by name, or you can iterate over all of them if you need to, e.g. if you need to dipose one object you can use

objects["Player"].Dispose();
objects.Remove("Player");

and if you need to dispose of everything at once (e.g. the game is over):

foreach (var o in objects) o.Dispose();
objects.Clear();

As a rule, if you find yourself putting numbers in variable names, you have probably made a mistake in your design. It is almost always better to put them into an array, list, or other data structure meant to contain multiple instances.

Upvotes: 1

Jaeho Lee
Jaeho Lee

Reputation: 42

It is possible with reflection.

public class MyClass
{
    public GameObject object1 = new GameObject("g1");
    public GameObject object2 = new GameObject("g2");
    public GameObject object3 = new GameObject("g3");

    public void AddObject()
    {
        List<GameObject> list = new List<GameObject>();

        for (int i = 1; i <= 3; i++)
        {
            var o = this.GetType().GetField($"object{i}").GetValue(this) as GameObject;    
            list.Add(o);
        }           
    }
}

Upvotes: 1

John3136
John3136

Reputation: 29266

There is no easy way to convert a string to a variable name, but depending what you are trying to do you could get rid of the object1 variables completely via:

// Personally I'd use a simple for loop instead of this 
foreach (var number in Enumerable.Range(1, 10))
{
    Objects.Add(new GameObject("Example Data"));
}

Edit: Using a range of 1..10 is going to confuse you somewhere down the road. In C# everything is 0 based. Just suck it up and don't try to pretend it isn't...

Upvotes: 4

Baddack
Baddack

Reputation: 2053

I would recommend a for loop. Loop through i times and create a new object and add it to your list.

for(int i = 0; i < 10; i++)
{
    GameObject ob = new GameObject("Example Data " + i);
    Objects.Add(ob);
}

Upvotes: 2

Related Questions