如果我尝试从类到接口的无效转换,那么编译器不会抱怨(错误发生在运行时);但是,如果我尝试对抽象类进行类似的转换,会抱怨。
class Program
{
abstract class aBaz
{
public abstract int A { get; }
}
interface IBar
{
int B { get; }
}
class Foo
{
public int C { get; }
}
static void Main()
{
Foo foo = new Foo();
// compiler error, as expected, since Foo doesn't inherit aBaz
aBaz baz = (aBaz)foo;
// no compiler error, even though Foo doesn't implement IBar
IBar bar = (IBar)foo;
}
}
为什么编译器拒绝从 Foo 到 IBar 的演员表,当它(似乎?)无效时?或者,为了解决这个问题,如果编译器允许对接口 IBar 进行“无效”转换,为什么它不允许类似的“无效”转换为抽象类 aBaz
答案 0 :(得分:8)
你需要了解.Net的继承系统,看看为什么这是有意义的。在.Net中,类可以仅从一个基类继承,但可以实现任意数量的接口。
class Program
{
abstract class aBaz
{
public abstract int A { get; }
}
interface IBar
{
int B { get; }
}
class Foo
{
public int C { get; }
}
class BarableFoo : Foo, IBar
{
public int C { get; }
}
static void Main()
{
// This is why the compiler doesn't error on the later cast
Foo foo = new BarableFoo();
// compiler error: aBaz is a class and the compiler knows that
// Foo is not a _subclass_ of aBaz.
aBaz baz = (aBaz)foo;
// no compiler error: the class Foo does not implement IBar, however at runtime
// this instance, "foo", might be a subclass of Foo that _implements_ IBar.
// This is perfectly valid, and succeeds at runtime.
IBar bar = (IBar)foo;
// On the other hand...
foo = new Foo();
// This fails at runtime as expected.
bar = (IBar)foo;
}
}
在问题中非常简单的原始示例中,似乎编译器可以检测到这个foo实例永远不会被转换为IBar,但这更像是一个“很好的”警告而不是问题语言正确性。
答案 1 :(得分:6)
强制转换的重点是抑制编译错误
(例如,如果您知道foo
实际上是实现接口的子类型的实例)
如果编译器可以证明演员阵容无法成功,那么它仍然会出错。 (例如,如果您转换为不在其层次结构中的类)
答案 2 :(得分:5)
并且为了表明编译器不是愚蠢的,当编译时编译失败时会出现这样的情况:如果编译器可以证明没有其他类可以从类派生,那么它将无法在编译时转换为接口:
sealed class NoBar
{
}
struct NoBarValue
{
}
IBar noBar = (IBar)(new NoBar()); // fails at compile time
IBar noBarValue = (IBar)(new NoBarValue()); // fails at compile time
在第一种情况下(NoBar
)类被明确地密封(因此没有派生类可以实现IFoo)并且编译器知道它本身不实现IBar
- 因此在编译时可能会失败。第二种情况(NoBarValue
)类似,唯一的区别是值类型(struct)被隐式密封。