为什么这个演员不可能?
interface IFolderOrItem where TFolderOrItem : FolderOrItem {} abstract class FolderOrItem {} class Folder : FolderOrItem {} abstract class Item : FolderOrItem {} class Document : Item {}
现在我想这样做:
class Something { IFolderItemOrItem SelectedItem { get; set; } void SomeMagicMethod() { this.SelectedItem = (IFolderOrItem)GetMagicDocument(); // bad bad bad ... ?? } IFolderOrItem GetMagicDocument() { return someMagicDocument; // which is of type IFolderOrItem } }
有没有可能让这个工作?
如果我读得正确…那么问题就是因为Foo : Bar
,这并不意味着ISomething
……
在某些情况下,C#4.0中的差异可能是一种选择。 或者,有时您可以使用通用方法执行某些操作(但不确定它在这方面会有所帮助)。
您在C#3.0(及以下)中最接近的可能是非通用的基本接口:
interface IFolderOrItem {} interface IFolderOrItem : IFolderOrItem where TFolderOrItem : FolderOrItem { }
通常,基接口将具有例如Type ItemType {get;}
以指示所考虑的实际类型。 然后用法:
IFolderOrItem SelectedItem { get; set; } ... public void SomeMagicMethod() { this.SelectedItem = GetMagicDocument(); // no cast needed // not **so** bad }
根据规范,这涉及§25.5.6(ECMA 334 v4):
25.5.6转换
构造类型遵循与非generics类型相同的转换规则(第13节)。 在应用这些规则时,构造类型的基类和接口应按照§25.5.3中的描述确定。
除了§13中描述的那些之外,构造的引用类型之间不存在特殊转换。 特别是,与数组类型不同,构造的引用类型不允许共变转换(第19.5节)。 这意味着类型
List
没有到List
转换(隐式或显式),即使B
是从A
派生A
。 同样,从List
到List
不存在转换。[注意:这个的基本原理很简单:如果允许转换为
List
,那么显然,可以将类型A
值存储到列表中。 但是,这会破坏类型为List
的列表中的每个对象始终为B
类值的不变量,否则在分配到集合类时可能会发生意外故障。 结束说明]
这同样适用于接口。 这在C#4.0中有所改变,但仅在某些情况下。
就编译器而言, IFolderOrItem
和IFolderOrItem
是两种完全不同的类型。
Document
可以inheritanceItem
,但IFolderOrItem
不inheritanceIFolderOrItem
我依靠Marc或Jon发布指向C#规范相关部分的链接。
问题是,强制转换不适用于generics参数,而是作为整个类。 文档inheritance自Item,true,但IFolderOrItem
一个例子来理解它为什么这样工作:
假设IFolderOrItem公开一个方法,例如void Add(T element)。
您对IFolderOrItem的实现将假设参数是Document。
但是你把你的IFolderOrItem转换为IFolderItemOrItem,然后有人可以调用方法Create(T),其中T应该是一个Item。
从项目到文档的强制转换无效,因为项目不是文档。
执行此操作的唯一方法是创建接口的非generics版本,允许将对象作为参数,检查实现中对象的类型。