C# 为什么在将密封类强制转换到它可能实现的接口时会出现编译错误?
下面的代码给出了一个编译器错误CS0030(使用VS 2012的C#编译器编译),尽管cast可能在运行时成功。删除C# 为什么在将密封类强制转换到它可能实现的接口时会出现编译错误?,c#,generics,compiler-errors,C#,Generics,Compiler Errors,下面的代码给出了一个编译器错误CS0030(使用VS 2012的C#编译器编译),尽管cast可能在运行时成功。删除sealed关键字,使用as强制转换,或向对象添加中间强制转换,都会使错误消失 public interface IFunny<out T> { } public sealed class Funny<T> : IFunny<T> { public IFunny<TOther> Cast<TOther>
sealed
关键字,使用as
强制转换,或向对象添加中间强制转换,都会使错误消失
public interface IFunny<out T> { }
public sealed class Funny<T> : IFunny<T>
{
public IFunny<TOther> Cast<TOther> ()
{
// error CS0030: Cannot convert type Funny<T>' to 'IFunny<TOther>'.
return (IFunny<TOther>) this;
}
}
公共接口IFunny{}
公共密封类有趣:我很有趣
{
公共IFunny演员阵容()
{
//错误CS0030:无法将类型“Funny”转换为“IFunny”。
返回(IFunny)这个;
}
}
在我看来,编译器只对密封类使用了一种启发式方法,这种方法在泛型接口实现中过于严格
它是否真的太严格了(在bug的意义上),还是有一个很好的理由来解释这个错误
更新:对我的问题的澄清:编译器无法确定编译时与T
之间是否存在关系。如果TOther
相同或是T
的基类,则在运行时强制转换将成功,而在所有其他情况下,强制转换都将失败。无论是否密封,这都是正确的
C#编译器通常不会阻止可能在运行时成功的强制转换。(例如,我可以将静态类型的object
实例强制转换为IComparable
,如果该实例没有真正实现该接口,则会导致运行时异常。)为什么在这种密封的情况下会这样做?在编译时不能确定TOther和t之间的关系
因此,基本上,您希望将IFunny
转换为一个IFunny
,例如,它将不起作用。由于它是密封的
类,程序员无法继承它。为了拥有强制转换对象的特权,您需要一个继承层次结构
但是,在这种情况下,sealed
关键字保证编译器在任何情况下都不能将TOther
类型设置为T
(即不能继承)。因此出现了错误
删除sealed
关键字会产生机会,因为TOther
可能属于T
类型。因此错误消失。在T
和之间是否存在关系?编译器怎么会知道这一点?我想编译器会拒绝这一点,因为T和TOther并不总是兼容的<代码>((IFunny)new fully())
可能会起作用…看看前面的问题;它有一些相关信息:[Sealed关键字影响强制转换][1][1]:因为T和TOther之间没有关系,所以编译器不可能知道如何强制转换。但是如果您改为将作为IFunny
返回,这将起作用,因为强制转换的返回值也可以为null。@w0lf,Grumbler,Marius-如果类未标记为sealed
,但已编译,则同样适用。Mihirj的回答更为详细:)在编译时没有可以确定的关系(TOther和T之间),但在运行时很有可能存在这种关系。那么为什么编译器会阻止强制转换呢?我不明白这一点。被密封
不会阻止你拥有一个有趣
并在上面调用演员
。密封
保证有趣
不能被继承。密封
如何保证编译器不能是t
类型?它根本不会影响T
和到,对吗?首先,TOther
可以和T
一样,那么演员阵容就会成功。其次,TOther
可以是T
的基类,在这种情况下它也可以工作。编译器无法判断强制转换是否会成功,AFAICs。编写编译器时,密封类型不可能满足任何未明确记录为实现的接口。确定类是否可以实现接口的代码可能就是基于这个假设设计的。尽管这个假设不再成立,但从事编译器工作的人可能还没有来得及修复编译器以适应这个事实。