2011-05-06 59 views
9

HI, 我有要求在运行时使用反射为列表对象创建实例。比如我有2类,如下面,如何使用反射在C#文件中创建列表<T>实例使用反射

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

另一类Class3在运行时创建的Class1实例后,我想分配值类的所有属性。在这种情况下,Class2ListList<Class2>的财产。 在运行时,我不知道List<Class2>的班级类型。如何在运行时初始化属性,即类别List<Class2>

任何建议都非常赞赏...

回答

17

而不是怀疑你的动机或者尝试拆洗你在做什么 - 我只是要回答这个问题的称号。

给你有一个代表类型参数是在运行时传递给List<>类型的类型实例listElemType

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

然后你就可以用列表的工作通过它的IList接口实现。

或者事实上,您可以在MakeGenericType呼叫处停下来,并使用它在Activator.CreateInstance的呼叫中生成的类型 - 就像Daniel Hilgarth的回答一样。

然后,给出一个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(); 

以获得该实例的所有公共属性。然而,仅仅能够创建一个列表实例并不能真正帮助你 - 你将不得不有一个更通用的解决方案来应对任何类型。除非你打算专门针对列表类型。

听起来像你对我可能需要初始化Class 1的List属性的公共接口或基...

+0

而不是为GetConstructor和Invoke调用创建零长度的数组,您可以使用'Type.EmptyTypes'作为GetConstructor,并将'null'传递给Invoke。此外,你必须投入由Invoke返回的对象:'var listInstance =(IList)(typeof(List <>).MakeGenericType(listElemType).GetConstructor(new Type [0]).Invoke(new object [0] ));' – phoog 2011-05-06 16:18:24

+0

谢谢 - 我知道'Type.EmptyTypes'和'null'到'Invoke',但我只是很快就把它撞出来......然而,失败的演员是因为我想添加IList一点之后,我会痛骂代码! 将更新。 – 2011-05-06 16:29:42

+0

就像我在找什么 – ArhiChief 2015-04-03 10:40:01

0

为什么你需要使用反射来设置属性?
您创建的Class1实例后,你可以简单地设置属性:

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

感谢您的回复。然而,我不知道class1在运行时有什么属性。例如,我给了Class2,实际上我不知道类的类型。那我该怎么做。 – Ananya 2011-05-06 09:21:54

0

这里的样本(不正确的错误处理!)。 如果你有一个接口,你想在你的对象的属性/字段中填充/初始化什么? 你想为其他对象类型填充什么(可能有多于1个构造函数参数)?

也许控制容器的反转将竭诚为您服务您的解决方案 (例如像Ninject http://ninject.org/,Spring.Net http://www.springframework.net/,统一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<>); 
     } 
    } 
}