2011-05-06 83 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<>); 
     } 
    } 
}