interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {}
abstract class FolderOrItem {}
class Folder : FolderOrItem {}
abstract class Item : FolderOrItem {}
class Document : Item {}
现在我正试图这样做:
class Something
{
IFolderItemOrItem<Item> SelectedItem { get; set; }
void SomeMagicMethod()
{
this.SelectedItem = (IFolderOrItem<Item>)GetMagicDocument();
// bad bad bad ... ??
}
IFolderOrItem<Document> GetMagicDocument()
{
return someMagicDocument; // which is of type IFolderOrItem<Document>
}
}
有可能让这个工作吗?
答案 0 :(得分:13)
如果我正确阅读了...那么问题就在于Foo : Bar
,不意味着ISomething<Foo> : ISomething<Bar>
......
在某些情况下,C#4.0中的差异可能是一种选择。或者,有时您可以使用通用方法执行某些操作(但不确定它会对此有所帮助)。
您在C#3.0(及以下)中最接近的可能是非通用的基本接口:
interface IFolderOrItem {}
interface IFolderOrItem<TFolderOrItem> : 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转化次数
构造类型遵循相同的转换规则(§13) 和非泛型类型一样。申请时 这些规则,基类和 构造类型的接口应 按照§25.5.3中的描述确定。
之间不存在特殊转换 构造的引用类型除了 第13节中描述的那些。特别是, 与数组类型不同,构造 引用类型不允许 共变体转换(第19.5节)。这个 表示类型
List<B>
没有 转换(隐含或 显式)到List<A>
,即使B
是 源自A
。同样,没有 转换从List<B>
到。{List<object>
。[注:理由 这很简单:如果转换为 允许
List<A>
,显然, 可以将A
类型的值存储到其中 列表。但是,这会破裂 一个中每个对象的不变量 类型List<B>
的列表始终是值 类型B
,或意外失败 分配时可能会发生 集合类。结束说明]
这同样适用于接口。这会更改C#4.0中的位,但仅限于某些情况。
答案 1 :(得分:6)
就编译器而言,IFolderOrItem<Document>
&amp; IFolderOrItem<Item>
是两种完全不同的类型。
Document
可以继承Item
,但IFolderOrItem<Document>
不会继承IFolderOrItem<Item>
我依靠Marc或Jon发布指向C#规范相关部分的链接。
答案 2 :(得分:3)
问题在于,强制转换对泛型参数不起作用,但对整个类起作用。文档继承自Item,true,但是IFolderOrItem&lt;文件&GT;不继承自IFolderOrItem&lt;项目&gt;,也不以任何方式与之相关。
答案 3 :(得分:2)
了解其工作方式的一个例子:
假设IFolderOrItem公开了一个方法,例如,void Add(T element)。
您对IFolderOrItem的实现将假设该参数是Document。
但是你把你的IFolderOrItem转换为IFolderItemOrItem,然后有人可以调用方法Create(T),其中T应该是一个Item。
从项目到文档的强制转换无效,因为项目不是文档。
执行此操作的唯一方法是创建非泛型版本的接口,允许将对象作为参数,检查实现中对象的类型。