为什么这个演员不可能?

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 : 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 。 同样,从ListList不存在转换。

[注意:这个的基本原理很简单:如果允许转换为List ,那么显然,可以将类型A值存储到列表中。 但是,这会破坏类型为List的列表中的每个对象始终为B类值的不变量,否则在分配到集合类时可能会发生意外故障。 结束说明]

这同样适用于接口。 这在C#4.0中有所改变,但仅在某些情况下。

就编译器而言, IFolderOrItemIFolderOrItem是两种完全不同的类型。

Document可以inheritanceItem ,但IFolderOrItem不inheritanceIFolderOrItem

我依靠Marc或Jon发布指向C#规范相关部分的链接。

问题是,强制转换不适用于generics参数,而是作为整个类。 文档inheritance自Item,true,但IFolderOrItem 不从IFolderOrItem inheritance,也不以任何方式与它相关。

一个例子来理解它为什么这样工作:

假设IFolderOrItem公开一个方法,例如void Add(T element)。

您对IFolderOrItem的实现将假设参数是Document。

但是你把你的IFolderOrItem转换为IFolderItemOrItem,然后有人可以调用方法Create(T),其中T应该是一个Item。

从项目到文档的强制转换无效,因为项目不是文档。

执行此操作的唯一方法是创建接口的非generics版本,允许将对象作为参数,检查实现中对象的类型。