2013-05-13 124 views
3

考虑下面的类和接口:泛型和接口问题

public class Test<T> 
{ 
} 

public interface ITesting<T> 
{ 
    Test<T> LoadTest(); 
} 

我可以添加一个类有以下:

public class TestManager : ITesting<object> 
{ 
    #region ITesting 

    public Test<object> LoadTest() 
    { 
     return new Test<object>(); 
    } 

    #endregion 
} 

的正常工作和不引发错误。如果我尝试用下面的来替代类:

public class TestDerived : Test<object> 
{ 
} 

public class TestDerivedManager : ITesting<object> 
{ 
    #region ITesting 

    public TestDerived LoadTest() 
    { 
     return new TestDerived(); 
    } 

    #endregion 
} 

我现在得到以下错误:

 
Error 'TestDerivedManager' does not implement interface member 'ITesting.LoadTest()'. 'TestDerivedManager.LoadTest()' cannot implement 'ITesting.LoadTest()' because it does not have the matching return type of 'Test'. 

但对我来说,好像这应该工作作为TestDerivedTest<object>。我显然在这里没有正确理解某些东西。有人可能指出我为什么这是不正确的细节?可能我会怎样做才能纠正它?

+3

我注意到,这种行为与泛型没有任何关系。如果你有'interface I {Animal M(); } class C:I {public Giraffe M(){return new Giraffe(); }}'你会得到同样的错误。 – 2013-05-13 15:00:59

回答

6

你想被称为返回类型的协方差的特征。这是C++的一个特性,但不是c#的特性,所以你必须做错误说的。

我建议你制作一个明确的接口实现,调用你的公共方法。这样你就能得到两全其美的好处。

4

将方法的返回类型更改回Test<object>,它应该可以工作。返回类型是实现接口时的合同的一部分。您仍然可以返回TestDerived,因为它是Test<object>

+2

它会,但我不认为这解释了为什么它不工作时,TestDerived实际上是测试 cgatian 2013-05-13 13:42:50

6

一个TestDerivedTest<object>,是的,但Test<object>一个TestDerived

合同说ITesting<object>有一个方法,可以返回任何Test<object>。不只是一个特例(TestDerived)。

为了使您的代码的工作,将其更改如下:

public class TestDerivedManager : ITesting<object> 
{ 
    public Test<object> LoadTest() 
    { 
     return new TestDerived(); 
    } 
} 
3

你在找什么叫做“return type covariance”,不幸的是不被C#支持。即使该返回类型来自原始返回类型,也不能覆盖(或实现)具有与原始签名不同的返回类型的方法。

你能做什么(可能是也可能不是一个好主意)是显式地实现接口,并有一个调用返回你正在寻找更窄类型的公共方法:

public class TestDerived : Test<object> 
{ 
} 

public class TestDerivedManager : ITesting<object> 
{ 
    public TestDerived LoadTest() 
    { 
    return new TestDerived(); 
    } 

    Test<object> ITesting<object>.LoadTest() 
    { 
    return this.LoadTest(); 
    } 
} 

那为您的实施增加了一层额外的复杂功能,但它也为您提供了您所需的公共合同,以及与界面的兼容性。

0

每个人都有很好的技术答案,但没有人解释为什么。所以我想我会给出一个关于界面的例子。

接口编程的一般方法是你应该实现接口中描述的确切的方法或属性。比方说,你有接口:

public interface ITesting<T> 
{ 
    Test<T> LoadTest(); 
} 

在消费这个接口的使用应该是这样的:

ITesting<object> testingLoader = GetTestingLoader(); 
Test<object> testingLoader.LoadTest(); 

如果您使用的接口访问对象,你不知道实现。您只知道LoadTest()方法的接口ITesting<T>将返回Test<T>

当您看到上面的消费者示例时,它会有意义。你(和编译器)不会(也不会)知道接口ITesting<object>有一个方法Test<object> LoadTest(),除非你声明它。如果您尝试使用实施了ITesting<object>但没有Test<object> LoadTest()方法的对象,会发生什么情况?它会错误吗?

这是继LSV principle之后。

+0

Erhm,不,你错了。谈论LSP:我应该能够将一个TestDerivedManager对象视为“ITesting ”,在其上调用“LoadTest”并获得“Test ”(如接口指定的)。该实现返回一个'TestDerived',它是一个'Test '。所以一切都很好,没有LSP违规,代码应该工作。没有错误。只有警告:有些语言支持它,但不支持C#。 – Virtlink 2013-05-13 17:25:17

+0

哦,我明白了,谢谢你帮我解决问题 – Fendy 2013-05-14 05:07:46