2010-09-08 61 views
3

爲什麼不能正常工作?多態性爲接口指定的屬性

public class ClassOptions {} 

public interface Inode { 
    ClassOptions Options {get;} 
}    

public class MyClass : Inode { 
    public ClassOptions Options { get; set; } 
}   

public class ClassDerivedOptions : ClassOptions { 
} 

public class MyDerivedClass : Inode { 
    public ClassDerivedOptions Options { get; set; } << does not implement INode... 
} 

[編譯器的消息告訴我,爲什麼它打破了,但我想知道爲什麼後面編譯犯規讓這個通過推理 - 也如果有任何變通? - 謝謝]

+0

你得到的編譯器信息是什麼? – FacticiusVir 2010-09-08 16:57:19

+0

[「返回派生類型時接口未實現」的可能的重複](http:// stackoverflow。com/questions/1121283/interface-not-implemented-when-returning-derived-type) – 2010-09-08 17:16:47

回答

8

它不起作用,因爲INode接口顯式調用類型爲ClassOptions的Options屬性。 C#不支持返回類型協變(這是你在這種情況下要求的)。

對於它的價值,這裏還有微軟連接語言功能要求專門爲返回類型的協方差:

Need covariant return types in C#/all .NET languages

如果你看一下頁面,他們也提到,共同的解決辦法是使用顯式接口實現:

public class MyDerivedClass : INode 
{ 
    public ClassDerivedOptions Options { get; set; } 
    public ClassOptions INode.Options { get { return Options; } } 
} 
+1

乾杯,隊友。這是很好的信息。 +1 – 2010-09-08 17:14:12

+0

感謝您的答案和連接鏈接。 – GreyCloud 2010-09-09 08:18:30

3

它不起作用,因爲一個接口定義了一個契約,並且當你實現這個契約時,方法簽名必須完全匹配。一個可能的解決方法是使用一個通用的接口:

public class ClassOptions 
{ } 

public class ClassDerivedOptions : ClassOptions 
{ } 

public interface INode<T> where T : ClassOptions 
{ 
    T Options { get; } 
}    

public class MyClass : INode<ClassOptions> 
{ 
    public ClassOptions Options { get; set; } 
}   

public class MyDerivedClass : INode<ClassDerivedOptions> 
{ 
    public ClassDerivedOptions Options { get; set; } 
} 
+0

感謝你的工作,它看起來比別人建議的更優雅。 – GreyCloud 2010-09-09 08:18:59

1

標準的方式來處理這種情況是實現明確的接口:

public class MyDerivedClass : Inode { 

    // New, more specific version: 
    public ClassDerivedOptions Options { get; set; } 

    // Explicit implementation of old, less specific version: 
    ClassOptions Inode.Options 
    { 
     get { return Options; } 
    } 
} 

這是最老IList實現仿製藥之前是如何工作的,例如:指定一個更具體的T this[int index]屬性,然後顯式實現object IList.this[int index],當set被一個錯誤類型的對象調用時拋出異常。

在您發佈的示例代碼,你甚至不需要明確set,因爲這是不是你的Inode接口的成員。

4

賈斯汀指出,你想要的功能被稱爲「返回類型協方差」,它是不是在C#的支持,或者,對於這個問題,在CLR類型系統。

雖然它經常被要求,但是這個功能很快就不可能實現(*)。由於在CLR中不支持,爲了實現它,我們只需生成所有爲您執行呼叫轉發的幫助程序方法。由於您已經可以用少量代碼「手動」執行該操作,因此編譯器爲您執行該操作幾乎沒有附加值。 (和as another question today notes, people sometimes get confused or irritated when the compiler generates a method to do interface forwarding on your behalf。)

不要誤解我的意思;我可以看到它是如何派上用場的,我已經在C++中使用了這個特性。但是每當它出現在C#程序中時,我發現我可以很輕鬆地解決它的缺失。 (*)當然五年前,我會說有關命名參數和可選參數的完全相同的東西,現在他們在C#4中。它可能的一個不太可能實現的功能,但是需求必須相當高。