2013-04-11 177 views
2

我有這個期望的類層次結構:C#實現接口方法與子類類型的參數

interface IClass 
{ 
    string print(IClass item); 
} 

class MyClass : IClass 
{ 
    // invalid interface implementation 
    // parameter type should be IClass not MyClass 
    string print(MyClass item) 
    { return item.ToString(); } 
} 

我試圖通過使用泛型類型作爲未來沒有成功解決接口的實現問題:

interface IClass 
{ 
    string print<T>(T item) where T : IClass; 
} 

class MyClass : IClass 
{ 
    string print<T>(T item) where T : MyClass 
    { return item.ToString(); } 
} 

我該怎麼辦?

+0

您應該使接口本身具有通用性併爲實現類提供所需的類型。 – Rik 2013-04-11 13:19:00

+1

如何在print方法中不使用參數並使每個子類將IClass實現注入到構造器或Sertter中。 – 2013-04-11 13:19:35

+1

toString方法繼承自Object,所以爲什麼你真的需要'print(MyClass item)'而不是'print(Object item)'? 你隱藏這種方法嗎? – Thomas 2013-04-11 13:19:49

回答

11

製作接口通用

interface IClass<T> where T : IClass<T> 
{ 
    string print(T item); 
} 

class MyClass : IClass<MyClass> 
{ 
    public string print(MyClass item) 
    { 
     return item.ToString(); 
    } 
} 
+0

謝謝@MehmetAtaş,你救了我的命:) :) 它的工作 – Lio 2013-04-11 13:35:38

+2

請注意,雖然這確實有效,(1)它很混亂,並且(2)它不一定強制執行你想強制執行的限制。有關此模式的一些想法,請參閱http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx。 – 2013-04-11 13:45:02

+0

@Eric,你有什麼建議以更清晰的方式解決問題? – Lio 2013-04-12 10:14:33

0

你只需要通過的iCLASS作爲參數傳遞給你的方法。

interface IClass 
{ 
    string print(IClass item); 
} 

class MyClass : IClass 
{ 
    public string print(IClass item) 
    { return item.ToString(); } 
} 
+1

我的要求是,MyClass的打印方法應該接收完全MyClass的參數,而不是另一個IClass子類的參數。 – Lio 2013-04-11 13:39:02

+0

現在,如果我們忽略那個人應該編程接口 - 而不是實現。以下接口有什麼問題? interface IClass {string print(MyClass item); } – WPFAbsoluteNewBie 2013-04-11 14:10:19

+0

沒什麼。沒關係。但就像下面說的@Eric Lippert一樣,它很混亂 – vcRobe 2013-04-11 14:21:31

7

這有助於理解爲什麼這是非法的。你想要的功能是形式參數類型協方差,很少有語言提供它。 (艾菲爾,我認爲這是一個功能。)它在語言中不常見,因爲它不安全!讓我用一個例子來說明:

class Animal {} 
class Lion : Animal { public void Roar() { } } 
class Giraffe : Animal { } 
interface IFoo { void M(Animal a); } 
class C : IFoo 
{ 
    public void M(Lion lion) { lion.Roar(); } 
} 
class P 
{ 
    public static void Main() 
    { 
     IFoo foo = new C(); 
     foo.M(new Giraffe()); 
    } 
} 

而我們只是做了長頸鹿的咆哮。

如果你看看所有這些類型的轉換,唯一可以明顯違法的是匹配C.M(Giraffe)IFoo.M(Animal)

現在,正式參數類型逆變類型安全但它不是在C#中的法律除了在某些非常有限的情況下。如果C#支持它,它沒有,那麼你可以放心地做這樣的事情:

interface IBar { void M(Giraffe g); } 
class D : IBar 
{ 
    public void M(Animal animal) { ... } 
} 
class P 
{ 
    public static void Main() 
    { 
     IBar bar = new D(); 
     bar.M(new Giraffe()); 
    } 
} 

看看發生了什麼呢? IFoo.M說:「我可以帶長頸鹿」,C.M說:「我可以接受任何長頸鹿,因爲實際上我可以接受任何動物」。如果C#支持它,那將是類型安全的,但它僅以兩種方式支持它:

  • 反變換泛型委託和接口轉換。
  • 將方法組轉換爲委託類型的方法組轉換。

第一的一個例子是,IComparable<Animal>類型的表達式可以由相同的邏輯被分配給IComparable<Giraffe>類型的變量:比較兩個動物在需要比較兩個長頸鹿的方法,可以使用這樣的方法。這是在C#4

所述第二的一個例子是加入:

delegate void MyFunction(Giraffe g); 
... 
D d = new D(); 
MyFunction myfunc = d.M; 

再次,我們需要一個函數,一個長頸鹿,我們提供一個可以接收任意動物。此功能添加到C#2中。

相關問題