Как создать экземпляр List <T>в файле C # с помощью Reflection - PullRequest
9 голосов
/ 06 мая 2011

HI, У меня есть требование создать экземпляр для объекта списка во время выполнения, используя отражение. Например, у меня есть 2 класса, как показано ниже,

class Class1
{
   List<Class2> class2List;
   public List<Class2> Class2List
   {
        get;set;
   }
}
class Class2
{
    public string mem1;
    public string mem2;
}

После создания экземпляра Class1 во время выполнения в другом классе Class3 я хочу присвоить значения всем свойствам класса. В этом случае Class2List является свойством List<Class2>. Во время выполнения я не знаю тип класса List<Class2>. Как я могу инициализировать свойство, т.е. List<Class2> внутри class3 во время выполнения.

Любые предложения с благодарностью ...

Ответы [ 3 ]

18 голосов
/ 06 мая 2011

Вместо того, чтобы ставить под сомнение ваши мотивы или пытаться отменить то, что вы делаете - я просто собираюсь ответить на вопрос в заголовке.

Если у вас есть экземпляр типа listElemType, который представляет типаргумент, который должен быть передан типу List<> во время выполнения:

var listInstance = (IList)typeof(List<>)
  .MakeGenericType(listElemType)
  .GetConstructor(Type.EmptyTypes)
  .Invoke(null);

И затем вы можете работать со списком через реализацию интерфейса IList.

Или, действительно,вы можете остановиться на вызове MakeGenericType и использовать тип, который он генерирует при вызове Activator.CreateInstance - как в ответе Даниэля Хилгарта.

Затем, учитывая объект target, свойство которого вы хотите установить:

object target; //the object whose property you want to set
target.GetType()
  .GetProperty("name_of_property")        //- Assuming property is public
  .SetValue(target, listInstance, null);  //- Assuming .CanWrite == true 
                                          //  on PropertyInfo

Если вы не знаете свойств типа, представленного target, то вам нужно использовать

target.GetType().GetProperties();

, чтобы получить все открытые свойства этого экземпляра.Однако простое создание экземпляра списка на самом деле не поможет вам в этом - у вас должно быть более общее решение, способное справиться с любым типом.Если только вы не будете специально ориентироваться на типы списков.

Похоже, вам может понадобиться общий интерфейс или база ...

0 голосов
/ 06 мая 2011

Вот пример (без надлежащей обработки ошибок!), Который инициализирует свойство List класса Class1.Что вы хотите заполнить / инициализировать в свойстве / поле вашего объекта, если у вас есть интерфейс?Что вы хотите заполнить для других типов объектов (возможно, с более чем одним параметром конструктора)?

Возможно, инверсия контейнера управления послужит вам в вашем решении (как, например, Ninject http://ninject.org/, Spring)..Net http://www.springframework.net/, Unity http://unity.codeplex.com/) или элементы уже правильно инициализированы в объектах, которые вы используете.

using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    public sealed class Class1
    {
        //[1]better solution (this way you wouldn't require reflection at all)
        // private readonly List<Class2> _class2List = new List<Class2>();
        private List<Class2> _class2List;
        public List<Class2> Class2List 
        { 
            get { return _class2List; }
            set {
                    _class2List = value; //set not allowed if you apply [1] 
                }
        }
        public string TestPropertyToIgnore { get; set; }
    }

    public class Class2
    {
        public string Mem1;
        public string Mem2;
    }


    class Program
    {
        static void Main()
        {
            var typeClass1 = Type.GetType("ConsoleApplication3.Class1");
            var objectClass1 =  Activator.CreateInstance(typeClass1);

            foreach(var property in objectClass1.GetType().GetProperties())
            {
                var propertyType = property.PropertyType;
                if (!propertyType.IsClass 
                    || !property.CanRead 
                    || !property.CanWrite
                    || property.GetValue(objectClass1, null) != null
                    || !IsGenericListOfT(propertyType)
                    )
                {
                    continue;
                }

                property.SetValue(objectClass1, Activator.CreateInstance(propertyType), null);

            }

            //this would raise a NullReference exception if list is still null
            Console.WriteLine(((Class1) objectClass1).Class2List.Count);
        }

        private static bool IsGenericListOfT(Type propertyType)
        {
            return propertyType.IsGenericType
                   && propertyType.GetGenericTypeDefinition() == typeof (List<>);
        }
    }
}
0 голосов
/ 06 мая 2011

Зачем вам нужно использовать отражение, чтобы установить свойство?
После создания экземпляра Class1 вы можете просто установить свойство:

Class1 instance = Activator.CreateInstanc<Class1>();
instance.Class2List = new List<Class2>();
...