2013-03-24 77 views
5

我不知道發生了什麼在這裏,但我用下面的代碼得到一個編譯器錯誤:C#泛型接口協方差

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(); 
    } 
} 

爲什麼我會得到一個錯誤,如果PostIPost<User>一個亞型?我知道在這種情況下,我可以使用User而不是IUser<IPost<User>>,但我想知道爲什麼這不起作用。

+0

你可以開始[點擊這裏](http://blogs.msdn.com/b/ericlippert/archive/2007/10/26/covariance-and-contravariance-in-c-part-five-interface-variance.aspx) – 2013-03-24 07:14:41

回答

12

我將嘗試使用簡單的例子來解釋它。假設你有一個多類實現IPost<User>

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

那麼這個代碼將無法編譯:

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

因爲user.Post是具體的類Post這是不符合PicturePost兼容的(他們是兄弟姐妹)。

然後想象從你的問題該行已成功編譯:

// 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(); 

他們會完全編譯,但第二行將失敗,運行時錯誤!這是因爲user.Post的實際類型是Post而不是IPostPicturePost

因此,爲了實現類型安全,C#編譯器禁止在編寫這樣的代碼的機會時進行編譯。爲了確保您不會寫這樣的代碼,Post屬性應該是隻讀的:

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

現在,你將無法寫邪惡的代碼,並Post所有用途將是類型安全有關它的接口,因爲你可以只需得到它,而不是完全分配給它的接口的變量。但是這並不足以告訴編譯器,你的接口在輕的一面,你需要明確地指定你的類型參數只是而不是(你可以使用它,但是你不能傳遞它)。因此,具有低於實現的接口(注意out關鍵字),您的代碼將編譯:

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(); 

希望我保持它的簡單,並在同一時間沒有錯過點:)