5

ここで何が起こっているのかわかりませんが、次のコードを使用するとコンパイラ エラーが発生します。

namespace SO
{
    interface IUser<PostType>
    {
        PostType Post { get; set; }
    }

    interface IPost<UserType>
    {
        UserType User { get; set; }
    }

    class User : IUser<Post>
    {
        //Implementation
    }

    class Post : IPost<User>
    {
        //Implementation
    }

    class SomeOtherClass
    {
        // Compiler Error: Cannot implicitly convert type 'SO.User' to
        // 'SO.IUser<SO.IPost<SO.User>>'. An explicit conversion exists 
        // (are you missing a cast?)
        IUser<IPost<User>> user = new User();

        //Works Fine
        IUser<Post> user = new User();
    }
}

Postが のサブタイプである場合にエラーが発生するのはなぜIPost<User>ですか? この場合、Userの代わりに使用できることIUser<IPost<User>>はわかっていますが、これが機能しない理由を知りたいです。

4

2 に答える 2

12

簡単な例を使って説明しようと思います。を実装するクラスがもう 1 つあるとしますIPost<User>

class PicturePost : IPost<User>
{
    // Implementation
}

次に、このコードはコンパイルされません。

    IUser<Post> user = new User();
    user.Post = new PicturePost();

と互換性user.Postのない具体的なクラスであるため(兄弟です)。PostPicturePost

次に、質問の行が正常にコンパイルされたと想像してください。

    // C# compiler is so kind today and it compiled this.
    IUser<IPost<User>> user = new User();

user.Post今は型になるので、そのIPost<User>ような行をコーディングする可能性があります:

    IUser<IPost<User>> user = new User();
    user.Post = new PicturePost();

そして、それらは完全にコンパイルされますが、2行目は実行時エラーで失敗します! これは、 の実際の型がorでuser.PostPostないためです。IPostPicturePost

そのため、タイプ セーフを実現するために、C# コンパイラは、そのようなコードが記述される可能性がある場合、コンパイルを禁止します。このようなコードを書かないようにするために、Postプロパティは読み取り専用にする必要があります。

interface IUser<PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}

これで、悪意のあるコードを書くことができなくなり、インターフェースのすべての使用法Postがタイプセーフになります。これは、それを取得するだけで、そのインターフェースの変数に完全に割り当てることができるためです。

しかし、これは十分ではありません。ライト側のインターフェイスに、型パラメーターがアウトのみであることを明示的に指定する必要があることをコンパイラーに伝えるには(使用できますが、渡すことはできません)。したがって、以下のインターフェースの実装 (noticeoutキーワード) を使用すると、コードはコンパイルされます。

interface IUser<out PostType>
{
    PostType Post { get; } // No setter, this is readonly.
}

    // Both lines compile!
    IUser<IPost<User>> user = new User();
    IUser<Post> user1 = new User();

シンプルに保ち、同時に要点を見逃さなかったことを願っています:)

于 2013-03-24T08:07:04.620 に答える
0

インターフェースを共変にする必要があります。

interface IUser<out PostType>
{
    PostType Post { get; }
}

interface IPost<out UserType>
{
    UserType User { get;  }
}

http://msdn.microsoft.com/en-gb/library/ee207183.aspx http://msdn.microsoft.com/en-gb/library/dd799517.aspxを参照して ください。

于 2013-03-24T08:06:11.827 に答える