为什么在将类转换为未实现的接口时没有编译器错误?

时间:2012-09-09 01:09:35

标签: c# c#-4.0 interface casting abstract-class

如果我尝试从类到接口的无效转换,那么编译器不会抱怨(错误发生在运行时);但是,如果我尝试对抽象类进行类似的转换,抱怨。

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

3 个答案:

答案 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)被隐式密封。