2014-01-31 113 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。