为什么这个演员不可能?

And*_*air 4 c# oop generics

interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {}

abstract class FolderOrItem {}

class Folder : FolderOrItem {}

abstract class Item : FolderOrItem {}

class Document : Item {}
Run Code Online (Sandbox Code Playgroud)

现在我想这样做:

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>
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有可能让这个工作?

Mar*_*ell 13

如果我正确地读它...那么问题是,仅仅因为Foo : Bar,但这并不意味着ISomething<Foo> : ISomething<Bar>...

在某些情况下,C#4.0中的差异可能是一种选择.或者,有时您可以使用通用方法执行某些操作(但不确定它在这方面会有所帮助).


你在C#3.0(及以下)中最接近的可能是一个非通用的基本接口:

interface IFolderOrItem {}
interface IFolderOrItem<TFolderOrItem> : IFolderOrItem
    where TFolderOrItem : FolderOrItem { }
Run Code Online (Sandbox Code Playgroud)

通常,基本接口将具有例如a Type ItemType {get;}来指示所考虑的实际类型.然后用法:

IFolderOrItem SelectedItem { get; set; }
...
public void SomeMagicMethod()
{
    this.SelectedItem = GetMagicDocument(); // no cast needed
    // not **so** bad
}
Run Code Online (Sandbox Code Playgroud)

根据规范,这涉及§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,但只在某些情况下.


Bin*_*ier 6

就编译器而言,IFolderOrItem<Document>&IFolderOrItem<Item>是两种完全不同的类型.

Document可以继承Item,但IFolderOrItem<Document>不继承IFolderOrItem<Item>

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