2012-12-14 105 views
2

我有一本字典,我正在使用它來促進一些基於api版本號的內部路由。本質上發生的是我在字典中查找和操作,並嘗試將其稱爲RUN方法。但爲了做到這一點,我需要能夠將對象投射到它的界面上。這裏是我的意思是,這是字典:如何使用反射投射到通用界面?

public Dictionary<string, Type> Routing = new Dictionary<string, Type>(); 

    public VersionRouter() 
    { 
     Routing.Add("1.0", typeof(OperationV1<RequestObjectV1, ResponseObjectV1>)); 
     Routing.Add("2.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV1>)); 
     Routing.Add("3.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV2>)); 
    } 

能搶我,我要實例,像這樣的正確類型:

var myOperation = Routing["2.0"]; 

然後在正常情況下,我只是實例化和投這樣的:

var myInstance = (MyInterface) Activator.CreateInstance(myOperation); 

然而,接口是通用的,因爲它需要知道什麼Request和Response類型:

var myInstance = (MyInterface<TRequest, TResponse>) Activator.CreateInstance(myOperation); 

我不知道如何告訴它這些請求和響應類型在這個階段。我假設它可以用反射來完成。我發現我可以通過類似myOperation.GetGenericArguments()的方式獲得這些泛型參數,但我不確定在這個階段如何使用這些參數。有誰知道如何做到這一點?

回答

4

這本質上是不可能的。
在編譯時你不能表達這種類型,因爲直到運行時才知道類型參數。
因此,您不能投射到它或具有該類型的變量。

如果可能,您應該使接口協變,並將其強制轉換爲使用基本類型。

或者,您可以製作非通用或協變基礎接口並使用它。

+0

你能舉個例子嗎?我不確定我以前做過這樣的事情。 – Sinaesthetic

+0

你可以在這裏瞭解所有關於協變接口的知識:[http://msdn.microsoft.com/en-us/library/dd997386.aspx]其實質是你可以用類型的'out'關鍵字來定義你的接口,意味着該接口可以接受派生較少的類而不會出錯。儘管這是一個棘手的領域,但如果你不注意如何設計接口,可能會引入一些有趣的錯誤。 –

4

爲了在SLaks擴大回答:

有處理您的方案不符合邏輯的方式。你要做的是在運行時使用不同類型的代碼。這隻能通過建立2個獨立的代碼分支(可以完成)或回退到動態/反射來完成。爲了澄清這一點:

class Apple { } 
class Pear { } 

void Handle(object what) 
{ 
    // either 
if (what is Apple) {} 
else if (what is Pear) {} 

// or 
dynamic x = what; 
x.LetsHopeThisMethodExists(); 

// or 
what.GetType().GetMethod('lorem').Invoke(what, null); 
} 

現在我們可以聲明一個基本類型爲蘋果和梨兩個,即水果SLaks建議堅持。這樣,Handle可以接受一個水果,並對蘋果和梨上的常用功能執行邏輯。

這引發了一個問題,如何用泛型做到這一點。泛型默認情況下不支持差異,但在.NET 4.0中它肯定是可能的。您可以通過在type參數上應用out關鍵字來聲明一個接口(但只有一個接口)爲協變。這可以讓你做這樣的事情:

interface IFruit { } 
interface IBasket<out TFruit> where TFruit : IFruit { } 

class Apple : IFruit { } 
class Pear : IFruit { } 

class FruitBasket<TFruit> : IBasket<TFruit> where TFruit : IFruit { } 
void Handle(IBasket<IFruit> what) { } 

Handle(new FruitBasket<Apple>()); 
Handle(new FruitBasket<Pear>()); 
+0

簡明扼要但內容翔實的答案。 – ean5533