简体   繁体   中英

Dynamically adding items to a List<T> through reflection

Lets say I have this class

class Child {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Container {
    public List<Child> { get; set; }
}

I'm working on a deserializer of sorts and I want to be able to create and populate the Child list from the data retrieved. I've gotten this far (I've cut out a lot of handling for other types for this example so its unnecessarily "iffy" but bear with me):

var props = typeof(Container).GetProperties();

foreach (var prop in props) {
    var type = prop.PropertyType;
    var name = prop.Name;

    if (type.IsGenericType) {
        var t = type.GetGenericArguments()[0];

        if (type == typeof(List<>)) {
            var list = Activator.CreateInstance(type);
            var elements = GetElements();

            foreach (var element in elements) {
                var item = Activator.CreateInstance(t);
                Map(item, element); 

                // ??? how do I do list.Add(item) here?
            }

            prop.SetValue(x, list, null); // x is an instance of Container

        }
    }
}

I can't figure out how to cast list to essentially List<t.GetType()> so I can access the add method and add the item.

I would say you should cast down to System.Collections.IList and directly call the Add method. Pros: simple, no ugly reflection. Cons: causes boxing for Lists containing value types.

This should work unless I am really missing something.

Outside of the loop

var add = type.GetMethod("Add");

Inside the loop

add.Invoke(list, new[] { item });

You need to call type.MakeGenericType(type.GetGenericArguments()) , which will return the correct closed generic type. You would then need to reflectively call the Add method. The code should look something like this:

   Type listType = type.MakeGenericType(type.GetGenericArguments());
   MethodInfo addMethod = listType.GetMethod("Add");
   addMethod.Invoke(instance, new object[] { ... });

I'm not sure what you would use as instance , but this is the actual object on which the method will be invoked.

The better question to ask is why are you trying to do this? The .NET Framework already includes serializers that know how to do all of this type of work. If you can, you should be using one of those instead of trying to "roll your own".

this is what i do

    var genericType = _primaryType.GetGenericArguments().First();
    var type = typeof(List<>).MakeGenericType(genericType);
    IList o = (IList)Activator.CreateInstance(type);
    o.Add(x)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM