14

クラスからインターフェイスへの無効なキャストを試みても、コンパイラは文句を言いません(エラーは実行時に発生します)。ただし、抽象クラスと同様のキャストを試してみると、文句を言います

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への同様の「無効な」キャストを許可しないのはなぜですか。

4

3 に答える 3

11

これが理にかなっている理由を理解するには、.Netの継承システムを理解する必要があります。.Netでは、クラスは1つの基本クラスからのみ継承できますが、任意の数のインターフェースを実装できます。

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にキャスト可能になることは決してないことを検出できたようですが、それは言語の正確さの問題というよりも「必要な」警告です。

于 2012-09-09T01:42:42.043 に答える
7

キャストの要点は、そのコンパイラエラーを抑制することです。
(たとえば、それfooが実際にインターフェイスを実装するサブタイプのインスタンスであることがわかっている場合)

キャストが成功することが不可能であることをコンパイラーが証明できる場合でも、エラーが発生します。(たとえば、階層にないクラスにキャストした場合)

于 2012-09-09T01:12:28.970 に答える
6

そして、コンパイラが愚かではないことを示すために、コンパイル時にキャストが失敗するという実際のケースがあります。コンパイラがクラスから他のクラスを派生できないことを証明できる場合、コンパイル時にインターフェイスへのキャストに失敗します。

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それ自体が実装されていないことを認識しています。したがって、コンパイル時に失敗する可能性があります。2番目のケース(NoBarValue)も同様ですが、値型(struct)が暗黙的にシールされている点が異なります。

于 2012-09-09T03:57:30.140 に答える