2009-07-20 90 views
96

在C#我有以下目的:如何動態創建使用反射的通用C#對象?

public class Item 
{ } 

public class Task<T> 
{ } 

public class TaskA<T> : Task<T> 
{ } 

public class TaskB<T> : Task<T> 
{ } 

欲使用TASKA或TaskB C#反射(Activator.CreateInstance)動態地創建。然而,我不會事先知道類型,所以我需要動態創建基於字符串的TaskA,如「namespace.TaskA」或「namespace.TaskAB」。

回答

182

看看這個article,這simple example。同樣的在你的類快速翻譯...

var d1 = typeof(Task<>); 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

根據您的編輯:對於這種情況,你可以這樣做......

var d1 = Type.GetType("GenericTest.TaskA`1"); // GenericTest was my namespace, add yours 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

要看到我backtick1想出的名字泛型類的詳細信息,請參見this article

注意:如果您的泛型類可以接受多種類型,您必須包含逗號當你忽略類型名稱,例如:

Type type = typeof(IReadOnlyDictionary<,>); 
+0

是否需要反引號,即是否忽略,編譯器是否假設它爲1? – richard 2011-03-03 07:01:06

+7

感謝您將我的博客文章「使用反射實例化C#.Net中的泛型類」(http://omegacoder.com/?p=38)作爲「簡單示例」。 :-)我很高興這篇文章正在尋找新的生活。 – OmegaMan 2011-05-16 18:48:06

+0

如何使用`is`關鍵字比較泛型? – 2013-04-04 13:18:36

2

在我看來,你的示例代碼的最後一行應該簡單地:

Task<Item> itsMe = o as Task<Item>; 

或者我錯過了什麼?

6

事實上,你將無法寫出最後一行。

但你可能不希望創建對象,貪圖或創建它。你可能想在你新創建的實例上調用一些方法。

然後您就需要類似的接口:

public interface ITask 
{ 
    void Process(object o); 
} 

public class Task<T> : ITask 
{ 
    void ITask.Process(object o) 
    { 
     if(o is T) // Just to be sure, and maybe throw an exception 
     Process(o as T); 
    } 

    public void Process(T o) { } 
} 

,並稱之爲:

Type d1 = Type.GetType("TaskA"); //or "TaskB" 
Type[] typeArgs = { typeof(Item) }; 
Type makeme = d1.MakeGenericType(typeArgs); 
ITask task = Activator.CreateInstance(makeme) as ITask; 

// This can be Item, or any type derived from Item 
task.Process(new Item()); 

在任何情況下,你將不會被靜態轉換爲一種你不」事先知道(在這種情況下是「makeme」)。 ITask允許你達到你的目標類型。

如果這不是你想要的,你可能需要在你正在努力實現這個什麼更具體一點。

1

確保你這樣做是一個很好的理由,像下面這樣一個簡單的功能將允許靜態類型,並允許你的IDE做的事情,如「查找引用」與重構 - >重命名。

public Task <T> factory (String name) 
{ 
    Task <T> result; 

    if (name.CompareTo ("A") == 0) 
    { 
    result = new TaskA(); 
    } 
    else if (name.CompareTo ("B") == 0) 
    { 
    result = new TaskB(); 
    } 

    return result; 
} 
1

我知道這個問題已經解決了,但是爲了讀者的利益;如果你把所有參與爲字符串類型的,你可以做到這一點作爲一個班輪:

IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface); 

每當我做這種事情,我有,我想後面的代碼利用的接口,所以我已經將創建的實例鑄造到一個接口。

相關問題