2012-07-21 79 views
4

假設你有這樣的:接口實現的混亂

// General purpose 
public interface ISerializer 
{ 
    IDataResult Serialize<T>(T instance); 
} 

// General purpose 
public interface IDataResult 
{ 
} 

// Specific - and I implement IDataResult 
public interface IMyCrazyDataResult : IDataResult 
{ 
} 

public class MyCrazySerializer : ISerializer 
{ 
    // COMPILE ERROR: 
    // error CS0738: 'MyCrazySerializer' does not implement interface member 'ISerializer.Serialize<T>(T)'. 
    // 'MyCrazySerializer.Serialize<T>(T)' cannot implement 'ISerializer.Serialize<T>(T)' because it does 
    // not have the matching return type of 'IDataResult'. 
    public IMyCrazyDataResult Serialize<T>(T instance) 
    { 
     throw new NotImplementedException(); 
    } 
} 

爲什麼在世界上我能得到這個編譯錯誤?我尊重界面 - 事實上,我確實會間接返回一個IDataResult。是編譯器無法弄清楚這個問題,還是在某種程度上(在OO級別)有錯誤的地方?

我覺得有一個接口的整個觀點是,我可以保證一些實現,但讓我打開它來加載它。這就是我正在做的 - 但我得到一個編譯錯誤。

在我的真實代碼中,我希望返回類型更具體,因爲我在派生接口中有幾個額外的方法。如果我使用返回類型的MyCrazySerializer.Serialize類型的IDataResult,那麼intellisense只是顯示我和那些簡單的常用方法,我想在其中顯示更具體的接口。

我還能怎麼做到這一點?這段代碼有什麼問題?

+2

[C#是否支持返回類型協變?](http:// stackoverflow。com/questions/5709034/does-c-sharp-support-return-type-covariance) – Euphoric 2012-07-21 19:24:27

+0

@euphoric - 我同意,在其他帖子上有很多很好的信息。 – 2012-07-21 19:43:19

回答

5

C#不支持return type covariance,因此您需要實現與接口上顯示的方法完全相同的Serialize<T>方法。您可以實現它明確然而,這意味着它知道真正的類型的MyCrazySerializer可以訪問更具體的方法的任何客戶端:

public class MyCrazySerializer : ISerializer 
{ 
    public IMyCrazyDataResult Serialize<T>(T instance) 
    { 
     throw new NotImplementedException(); 
    } 

    IDataResult ISerializer.Serialize<T>(T instance) 
    { 
     return this.Serialize(instance); 
    } 
} 

正如評論指出的那樣,你可以簡單地調用更具體的版本在你明確的實現。

您可以使用如:

IMyCrazyDataResult result = new MyCrazySerializer().Serialize<int>(1); 
ISerializer serializer = (ISerializer)new MyCrazySerializer(); 
IDataResult = serializer.Serialize<int>(1); 
+0

我沒有想到這個!這確實給了我最想要的。我做ISerialier s = new MyCrazySerializer()。Seri ... intellisense首先顯示我的自定義界面,但是通過投射,我也可以看到IDataResult ...謝謝! – 2012-07-21 19:46:29

+0

如果你編寫顯式版本來調用另一個版本,你將得到一個+1:'IDataResult ISerializer.Serialize (T instance {return Serialize(instance);}'這當然是如果你這樣做的方式不能修改'ISerializer'界面 – 2012-07-21 20:12:28

+0

@Daniel - 是的,這是一個很好的建議 - 編輯 – Lee 2012-07-21 20:16:26

3

爲什麼世界上我會得到這個編譯錯誤?我尊重接口

不,你不是。您沒有返回IDataResult,而是IMyCrazyDataResult。是的,它從IDataResult繼承,但它不是與它相同。

說到界面,你不會得到方差 - 類型必須完全匹配。

+0

爲什麼?具有精確類型與派生類型的意義 - 這看起來像一個脆弱的想法。 – 2012-07-21 19:38:11

+0

@RobertSeder - 這就是語言設計者決定設計語言的方式。 – Oded 2012-07-21 19:40:21

3

由於您指定了與方法的返回類型不同的東西,因此您沒有實現接口契約,因此簽名必須完全匹配。這並不意味着你不能返回多個指定接口,下面是完美的罰款:

// General purpose 
public interface ISerializer 
{ 
    IDataResult Serialize<T>(T instance); 
} 

// General purpose 
public interface IDataResult 
{ 
} 

// Specific - and I implement IDataResult 
public interface IMyCrazyDataResult : IDataResult 
{ 
} 

public class MyCrazySerializer : ISerializer 
{ 
    public IDataResult Serialize<T>(T instance) 
    { 
     // return a IMyCrazyDataResult here 
    } 
} 
+0

我認爲OP已經證明了他爲什麼期望它能夠工作的足夠能力 – 2012-07-21 19:32:03

+0

爲什麼它需要完全匹配,而不尊重派生類型?爲什麼這麼脆弱的實現?爲什麼不允許面向對象的原則?爲什麼不允許派生類型 - 這是OO的核心!?!? – 2012-07-21 19:39:55

+0

請參閱[Eric Lippert的回答](http://stackoverflow.com/questions/4348760/c-sharp-covariant-return-types-utilizing-generics/4349584#4349584)(C#編譯器團隊的開發人員之一)那個話題。 – Femaref 2012-07-21 20:23:52

5

你可以建立自己的一種回報型的協方差在C#:

// General purpose 
public interface ISerializer<out TResult> where TResult : IDataResult 
{ 
    TResult Serialize<T>(T instance); 
} 

// General purpose 
public interface IDataResult 
{ 
} 

// Specific - and I implement IDataResult 
public interface IMyCrazyDataResult : IDataResult 
{ 
} 

public class MyCrazySerializer : ISerializer<IMyCrazyDataResult> 
{ 
    public IMyCrazyDataResult Serialize<T>(T instance) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Serialize返回類型明確指出是一些導出從IDataResult,而不是精確地TResult

+0

似乎我不應該這樣做 - 但這是行得通的。希望讓我的界面更清潔一些。 – 2012-07-21 19:47:48