2014-01-31 112 views
3

是否有人可以解釋爲什麼這代碼片段是不是工作?爲什麼不是一個castable到b? 我在考慮協變和逆變,但據我一致認爲這不適用於抽象類。類間的轉換與仿製藥

編譯錯誤: 無法將類型 'ConsoleApplication1.SVM' 到 'ConsoleApplication1.VMSBase' ConsoleApplication1 \ Program.cs的

class Program 
{ 
    static void Main(string[] args) 
    { 
     var a = new SVM(); 

     var b = (VMSBase<Model>)a; 
    } 
} 

class SVM : VMSBase<SpecialModel> 
{ 

} 

class VMSBase<TS> : VMBase<TS> where TS : Model 
{ 

} 

class VMBase<T> where T : Model 
{ 
} 

class SpecialModel : Model 
{ 

} 

class Model 
{ 

} 
+1

什麼是錯誤? –

+1

雖然我不能確定,因爲這個話題變得混亂,我相信解決方案正在改變'VMSBase '到'VMSBase '。如果這不起作用,它將是'in'修飾符。 –

+0

這是'out'修飾符上的[documentation](http://msdn.microsoft.com/zh-cn/library/dd469487.aspx)。 –

回答

6

SVMVMSBase<SpecialModel>一個亞型,因此它可以被轉換爲一個。

但是有VMSBase<SpecialModel>VMSBase<Model>之間沒有多態性關係,因爲一般類型參數TVMSBase<T>不變


爲了VMSBase<X>是的VMSBase<Y>一個亞型(其中XY亞型),T必須協變。您使用out關鍵字將其標記爲協變:VMSBase<out T>。然而,這迫使你使用類型T的返回值從所有成員(方法,屬性等),從未作爲輸入值(方法參數)。

還有另一個難題:C#只允許在接口上的差異。所以你必須將VMBase和VMSBase都變成接口。

class Program 
{ 
    static void Main(string[] args) 
    { 
     SVM a = new SVM(); 
     var b = a as IVMSBase<Model>; 
    } 
} 

class SVM : IVMSBase<SpecialModel> {} 

interface IVMSBase<out TS> : IVMBase<TS> where TS : Model {} 

interface IVMBase<out T> where T : Model {} 

更多信息:Covariance and Contravariance FAQ

1

底線是VMSBase<SpecialModel>是不一樣的VMSBase<Model>

這是一樣的道理,爲什麼這不會編譯:

List<ViewBase> list = new List<GridView>(); 

雖然GridView控件從ViewBase繼承。

它的語言是如何工作的,泛型你可能會說的限制。

0

想象一下,你可以合法地做演員。現在想象一下,我們這個方法定義了吃型號:

class VMSBase<TS> : VMBase<TS> where TS : Model 
{ 
    public void GobbleUpModel(TS model) 
    { 

    } 
} 

利用這一點,我們可以在下面的(奇怪,如果你以前沒有見過吧)的方式繞過類型安全:

//SpecialModel2 is some other subclass of Model, not related to SpecialModel 
SpecialModel2 incompatibleModel; 

var a = new VMSBase<SpecialModel>(); 

var b = (VMSBase<Model>)a; 

//forces a to gobble up a model that is incompatible with SpecialModel 
b.GobbleUpModel(incompatibleModel); 
0

爲什麼泛型是不是在C#變形的原因是因爲它會導致輸入問題:使用您的例子,假設VMSBase具有類型T名爲myProperty的的屬性。如果可以鑄造,你可以做類似的事情:

var a = new VMSBase<SpecialModel>(); 
var b = (VMSBase<Model>) a; 
b.MyProperty = new Model(); 

現在你只需設置b的值。MyProperty添加到Model的一個實例;但這與VMSBase中預期的類型不一致,實際上它是SpecialModel。