2015-10-20 31 views
2

我試圖讓所有這些映射器類有一個共同的基礎,當鑄造基地接口:使用協方差和多個通用參數

// base 
class BaseInput { public string BaseInputValue { get; set; } } 
class BaseOutput { public string BaseOutputValue { get; set; } } 

interface IMapper<InputType, out OutputType> 
    where InputType : BaseInput 
    where OutputType : BaseOutput 
{ 
    OutputType Map(InputType input); 
} 

// example implementation 
class Input : BaseInput { public string InputValue { get; set; } } 
class Output : BaseOutput { public string OutputValue { get; set; } } 

class MyMapper : IMapper<Input, Output> 
{ 
    public Output Map(Input input) 
    { 
     // custom mapping done here to Output 
     return new Output { /* mapping */ }; 
    } 
} 

此代碼來創建這些映射器的一個新的,並把它分配給基本編譯罰款:

var myBaseMapper = (IMapper<BaseInput, BaseOutput>) new MyMapper(); 

但我得到一個運行時錯誤:

Unable to cast object of type 'MyMapper' to type 'IMapper`2[UserQuery+BaseInput,UserQuery+BaseOutput]'.

如果我減少IMapperIMapper<out OutputType>它可以正常工作,但是這需要在MyMapper.Map中進行演員製作,這在每個映射器類中都有點麻煩。此外,這使我失去了決定使用哪個Mapper的信息,因此我不得不在其他地方定義這些信息。

這樣做只是不可能在C#或有沒有辦法做類似的事情嗎?如果不是,我將不得不重新考慮我的設計。

+1

申報'InputType'作爲協變:'接口IMapper <在的inputType,出輸出類型>' – MarcinJuraszek

+1

@MarcinJuraszek'InputType'將是* *逆變在這種情況下 – BradleyDotNET

+0

@MarcinJuraszek我試圖做'<在的inputType,出輸出類型>'之前只是爲了看到,但我得到了同樣的錯誤。順便說一下,我的意思是最初在標題中爲'out'寫'協變'。我混淆了他們。 –

回答

3

你不能這樣做,因爲它沒有任何意義,你的界面是逆變在InputType參數(或者,更確切地說,它是,如果你添加的in關鍵字添加到該參數)。要了解爲什麼這沒有意義,讓我們看看您的示例:

您希望IMapper<Input, Output>的實施可分配給IMapper<BaseInput, BaseOutput>。比方說,我們創造了一些新的子類的BaseInput,我們把它叫做MoreInput

class MoreInput : BaseInput 
{ 
    public string LotsOfInput { get; set; } 
} 

好了,現在讓我們說我們有他的屍體看起來像這樣的方法(和你想要的實際工作):

IMapper<BaseInput, BaseOutput> mapper = new MyMapper(); 
mapper.Map(new MoreInput()); 

好了,在這一點上沒有什麼是錯的:IMapper<BaseInput, BaseOutput>Map方法接受BaseInput作爲它的參數和MoreInputBaseInput,所以我們通話有效。

除非它不是,因爲Map方法我們真的調用預計的Input作爲它的參數和MoreInputInput。我們已經打破了類型系統。

這是編譯器告訴你什麼時候它不允許你隱式地進行賦值:這種轉換是不安全的。編譯器不能保證你期望的類型是你得到的類型。

+0

這很有道理。謝謝!我會想辦法做一個不同的方式。 –