2013-04-11 78 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中。

相关问题