Search code examples
c#system.reflection

How do I access List<int> value during reflection of a class?


I am fairly new to Reflection, but have been able to retrieve all fields of my passed class. Now I am trying to retrieve the values of each field, but I'm having an issue with List<T>.

I have a simple class for testing:

    public class MyTestClass
    {
        public string Name;
        public int Age;
        public bool Alive;
        public List<int> Counters;
        public List<string> People;
        public List<Tool> Tools;
        public string[] Stuff;
        public Tool[] NeededTools;

        public MyTestClass(string name, int age, bool alive = true)
        {
            Name = name;
            Age = age;
            Alive = alive;
            Counters = new List<int>();
            Counters.Add(7);
            People = new List<string>();
            People.Add("Seven");
            Tools = new List<Tool>();
            Stuff = new string[2];
            NeededTools = new Tool[3];
        }
    }

Here is the code I am using:

    private void AttachControl(object source, FieldInfo fi, Control control)
    {
        switch (fi.FieldType.Name)
        {
            case "Boolean":
                (control.Controls[fi.Name] as ComboBox).SelectedIndex = (fi.GetValue(source).ToString().ToUpper() == "TRUE") ? 1 : 0;
                break;
            case "List`1":
                Control listControl = control.Controls[fi.Name];
                var listType = fi.FieldType.GetGenericArguments();

                var listFields = listType[0].GetFields(
                                       BindingFlags.Public |
                                       BindingFlags.Instance
                                       );
                if (listFields.Length > 0)
                {
                    AttachToControls(listFields, listControl.Controls.Cast<Control>().ToArray());
                }
                else
                {
                    // *** Here is the issue ***
                    var values = fi.GetValue(source);
                    listControl.Controls[fi.Name].Text = values[0].ToString();
                }
                break;
            default:
                control.Controls[fi.Name].Text = fi.GetValue(source).ToString();
                break;
        }
    }

When I get to Counters I can retrieve the value var values = fi.GetValue(source); and during debug I can see the List with the value 7 in it, but it states

cannot apply indexing with [] to an expression of type object on the line: listControl.Controls[fi.Name].Text = values[0].ToString();

I assume I need to cast it, but it will not always be an int type. Do I need to write a section for every type or is there an easier way to accomplish what I need?

FYI - I am writing a Class Library that will allow me to pass any class in and auto create a form to edit all fields.


Solution

  • I'd suggest something along the lines of:

    var bob = values as IEnumerable;
    listControl.Controls[fi.Name].Text = bob?.Cast<object>()?.FirstOrDefault()?.ToString();
    

    Since the thing you want is a string (not a specific type) then the above code will work fine (assuming values is some form of an enumerable, like a list or an array).

    Note, in particular, that IEnumerable interface is this one, not the more commonly used IEnumerable<T>. This allows you to use it without a specific type.