Динамическое добавление элементов в список <T> через отражение

Предположим, что у меня этот класс

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

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

Я работаю над сортировщиком сортировки, и я хочу иметь возможность создавать и заполнять список Child из полученных данных. Я получил это далеко (я вырезал много обработки для других типов для этого примера, поэтому его излишне "iffy", но голый со мной):

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

        }
    }
}

Я не могу понять, как сделать list по существу List<t.GetType()>, чтобы я мог получить доступ к методу добавления и добавить элемент.

Ответ 1

Я бы сказал, что вы должны отказаться до System.Collections.IList и напрямую вызвать метод Add. Плюсы: просто, не уродливое отражение. Минусы: вызывает бокс для списков, содержащих типы значений.

Ответ 2

Это должно работать, если я действительно ничего не теряю.

Вне цикла

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

Внутри цикла

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

Ответ 3

Вам нужно позвонить type.MakeGenericType(type.GetGenericArguments()), который вернет правильный закрытый общий тип. Затем вам нужно будет рефлексивно вызвать метод Add. Код должен выглядеть примерно так:

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

Я не уверен, что вы использовали бы как instance, но это фактический объект, на который будет вызываться метод.

Лучше спросить, почему вы пытаетесь это сделать? В .NET Framework уже есть сериализаторы, которые знают, как выполнять весь этот вид работы. Если вы можете, вы должны использовать один из них вместо того, чтобы пытаться "сворачивать свои собственные".

Ответ 4

вот что я делаю

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