McG*_*gle 10 c# abstract-class casting interface c#-4.0
如果我尝试从类到接口的无效转换,那么编译器不会抱怨(错误发生在运行时); 但是,如果我尝试对抽象类进行类似的转换,它确实会抱怨.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器拒绝从Foo到IBar的转换,当它(似乎?)无效时?或者,为了解决问题,如果编译器允许对接口IBar进行 "无效" 转换,为什么它不允许对抽象类aBaz进行类似的"无效" 转换?
你需要了解.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;
}
}
Run Code Online (Sandbox Code Playgroud)
在这个问题非常简单原始的例子,它看起来像编译器可以检测到FOO的这个实例是永远不会被强制转换为伊巴尔,但更多的是"锦上添花",警告不是语言正确性的问题.
强制转换的重点是抑制编译器错误.
(例如,如果您知道这foo实际上是实现接口的子类型的实例)
如果编译器可以证明演员阵容无法成功,那么它仍然会出错.(例如,如果你投的类不在其层次结构)
并且为了表明编译器不是愚蠢的,当编译时编译失败时会出现这样的情况:如果编译器可以证明没有其他类可以从类派生,它将无法在编译时转换为接口:
sealed class NoBar
{
}
struct NoBarValue
{
}
IBar noBar = (IBar)(new NoBar()); // fails at compile time
IBar noBarValue = (IBar)(new NoBarValue()); // fails at compile time
Run Code Online (Sandbox Code Playgroud)
在第一种情况下(NoBar)类是显式密封的(因此没有派生类可以实现IFoo)并且编译器知道它没有实现IBar自身 - 因此在编译时可能会失败.第二种情况(NoBarValue)类似,唯一的区别是值类型(结构)被隐式密封.