Динамическое добавление элементов в список <T>через отражение - PullRequest
16 голосов
/ 10 октября 2009

Допустим, у меня есть этот класс

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

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

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

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()>, чтобы получить доступ к методу добавления и добавить элемент.

Ответы [ 4 ]

21 голосов
/ 10 октября 2009

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

19 голосов
/ 10 октября 2009

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

Вне петли

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

Внутри петли

add.Invoke(list, new[] { item });
1 голос
/ 10 октября 2009

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

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

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

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

0 голосов
/ 22 сентября 2016

это то, что я делаю

    var genericType = _primaryType.GetGenericArguments().First();
    var type = typeof(List<>).MakeGenericType(genericType);
    IList o = (IList)Activator.CreateInstance(type);
    o.Add(x)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...