C# 为什么这个演员不可能? 接口IFolderOrItem,其中TFolderOrItem:FolderOrItem{} 抽象类FolderOrItem{} 类文件夹:FolderOrItem{} 抽象类项:FolderOrItem{} 类文档:项{}

C# 为什么这个演员不可能? 接口IFolderOrItem,其中TFolderOrItem:FolderOrItem{} 抽象类FolderOrItem{} 类文件夹:FolderOrItem{} 抽象类项:FolderOrItem{} 类文档:项{},c#,generics,oop,C#,Generics,Oop,现在我正试着做这样的事情: interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {} abstract class FolderOrItem {} class Folder : FolderOrItem {} abstract class Item : FolderOrItem {} class Document : Item {} 分类 { IFolderItem Select

现在我正试着做这样的事情:

interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {}

abstract class FolderOrItem {}

class Folder : FolderOrItem {}

abstract class Item : FolderOrItem {}

class Document : Item {}
分类
{
IFolderItem SelectedItem{get;set;}
void SomeMagicMethod()
{
this.SelectedItem=(IFolderOrItem)GetMagicDocument();
//糟糕??
}
IFolderOrItem GetMagicDocument()
{
返回someMagicDocument;//类型为IFolderOrItem
}
}

有没有可能让它工作?

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

文档
可以继承
,但
IFolderOrItem
不继承
IFolderOrItem


我依靠Marc或Jon发布到C#spec相关部分的链接。

问题是cast不能处理泛型参数,而是处理整个类。文档继承自项,true,但IFolderOrItem不会继承自IFolderOrItem,也不会以任何方式与其相关。

如果我正确阅读它。。。那么问题是,仅仅因为
Foo:Bar
,这并不意味着
ISomething:ISomething

在某些情况下,C#4.0中的差异可能是一种选择。或者,有时您可以使用泛型方法来做一些事情(但不确定它在这里是否有用)


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

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>
    }
}

根据规范,这与§25.5.6(ECMA 334 v4)有关:

25.5.6换算

构造类型遵循相同的转换规则(§13) 非泛型类型也是如此。申请时 这些规则、基类和 构造类型的接口应 如§25.5.3所述确定

之间不存在特殊转换 构造的引用类型,而不是 第13条中所述的。特别地, 与数组类型不同,构造 引用类型不允许 共变体转换(§19.5)。这 表示类型
列表
没有 转换(隐式或非隐式) 明确)到
列表
,即使
B
是 源自
A
。同样地,没有 从
列表
列表

[注:理由如下: 这很简单:如果转换为
列表
是允许的,那么显然, 可以将
A
类型的值存储到 但是,这个列表将被打破 一个空间中每个对象的不变量 类型列表
list
始终是一个值 类型为
B
,或其他意外故障 分配到时可能发生 收集类别.结束注]


这同样适用于接口。这在C#4.0中有一点变化,但仅在某些情况下发生。

一个例子来理解它为什么会以这种方式工作:

假设IFolderOrItem公开了一个方法,例如voidadd(T元素)

IFolderOrItem的实现将假定参数是一个文档

但是如果您将IFolderOrItem转换为ifolderItem,那么有人可以调用Create(T)方法,其中T应该是一个项

从项到文档的转换无效,因为项不是文档


要做到这一点,唯一的方法是创建非通用版本的接口,允许对象作为参数,检查实现中对象的类型。

它抛出的错误消息是什么?编译时?不带强制转换=编译时;使用cast=runtime(根据您在我的回复中的评论,我在一个非通用的基本接口上添加了一些注释,至少可以让它工作起来)@downvoter:这会很有趣,为什么……哈哈——但我相信这是C#3.0规范中没有的东西之一,因为这不是一个考虑因素。不过,4.0规范中应该有一些东西。很棘手。。。它不是一个IFolderOrItem,所以除非你包装它,否则它不会工作。根据接口中的成员,它可能在4.0中起作用(使用额外的修改器)。除此之外。。。也许声明一个非泛型接口…您的泛型自由接口与抽象类(泛型自由接口+泛型接口)结合的解决方案正好击中要害。。。哇!非常感谢。
interface IFolderOrItem {}
interface IFolderOrItem<TFolderOrItem> : IFolderOrItem
    where TFolderOrItem : FolderOrItem { }
IFolderOrItem SelectedItem { get; set; }
...
public void SomeMagicMethod()
{
    this.SelectedItem = GetMagicDocument(); // no cast needed
    // not **so** bad
}