繁体   English   中英

为什么我可以抛出IList的不变性 <T> 远?

[英]Why can I cast the invariance of IList<T> away?

目前,我正准备为我的同事介绍C#中新的通用差异功能。 为了简化故事,我写了以下几行:

IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = formsList;

是的,这当然是不可能的,因为IList(Of T)是不变的(至少我的想法)。 编译器告诉我:

无法将System.Collections.Generic.IList<System.Windows.Forms.Form>类型隐式转换为System.Collections.Generic.IList<System.Windows.Forms.Control> 存在显式转换(您是否错过了演员?)

嗯,这是否意味着我可以强制进行显式转换? 我刚尝试过:

IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = (IList<Control>)formsList;

并且...它编译! 这是否意味着我可以抛弃不变性? - 至少编译器没问题,但我只是将前编译时错误转为运行时错误:

Unable to cast object of type 'System.Collections.Generic.List`1[System.Windows.Forms.Form]' to type 'System.Collections.Generic.IList`1[System.Windows.Forms.Control]'.

我的问题:为什么我可以将IList<T> (或我的实验的任何其他不变界面)的不变性抛弃了? 我是否真的抛弃了不变性,或者这里发生了什么样的转换(因为IList(Of Form)IList(Of Control)是完全不相关的)? 这是C#的一个黑暗角落,我不知道?

从本质上讲,类型可以实现IList<Control> 以及 IList<Form>因此转换成功是可能的 - 因此编译器暂时允许它(除此之外:它可能在这里更聪明并产生警告,因为它知道引用对象的具体类型,但不知道。我不认为产生编译器错误是合适的,因为它不是实现新接口的类型的重大变化)。

作为这种类型的一个例子:

public class EvilList : IList<Form>, IList<Control> { ... }

在运行时发生的只是CLR类型检查。 您看到的例外情况表示此操作失败。

为演员生成的IL是:

castclass [mscorlib]System.Collections.Generic.IList`1<class [System.Windows.Forms]System.Windows.Forms.Control>

来自MSDN

castclass指令尝试将堆栈顶部的对象引用(类型O)强制转换为指定的类。 新类由指示所需类的元数据标记指定。 如果堆栈顶部的对象类没有实现新类(假设新类是接口)并且不是新类的派生类,则抛出InvalidCastException。 如果对象引用是空引用,则castclass成功并将新对象作为空引用返回。

如果无法将obj强制转换为类,则抛出InvalidCastException。

我怀疑在这种情况下,如果您尝试将新的TextBlock添加到controlsList中,则会抛出运行时异常。 TextBlock将符合controlsList的合同,但不符合formsList。

IList<Form> formsList = new List<Form> { new Form(), new Form() }; 
IList<Control> controlsList = (IList<Control>)formsList; 
controlsList.Add(New TextBlock); // Should throw at runtime.

在这种情况下,类型安全不变通常会将其作为运行时异常。 在这种情况下,您可以安全地将controlsList声明为IEnumerable而不是IList(假设.Net 4.0),因为IEnumerable被声明为协变(IEnumerable)。 这解决了尝试向控件列表添加错误类型的问题,因为.add(和其他输入方法)在out接口中不可用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM