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
}

我现在收到以下错误:

错误“TestDerivedManager”未实现接口成员“ITesting.LoadTest()”。“TestDerivedManager.LoadTest()”无法实现“ITesting.LoadTest()”,因为它没有匹配的返回类型“Test”。

但对我来说,这似乎应该按原样TestDerived工作Test<object>。我显然在这里没有正确理解某些东西。有人可以指出我为什么这是不正确的详细信息吗?可能我会做些什么来纠正它?

4

5 回答 5

6

ATestDerived是 a ,是Test<object>,但 aTest<object>不是a 。TestDerived

合同说ITesting<object>有一个方法可以返回任何Test<object>. 不只是一种特殊情况(TestDerived)。

要使您的代码正常工作,请按如下方式进行更改:

public class TestDerivedManager : ITesting<object>
{
    public Test<object> LoadTest()
    {
        return new TestDerived();
    }
}
于 2013-05-13T13:43:53.020 回答
6

您想要的功能称为返回类型协方差。这是 c++ 的一个特性,但不是 c# 的特性,所以你必须按照错误所说的去做。

我建议您创建一个调用您的公共方法的显式接口实现。这样你就可以两全其美了。

于 2013-05-13T14:13:24.820 回答
4

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

于 2013-05-13T13:41:28.023 回答
3

您要查找的内容称为“返回类型协方差”,不幸的是 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();
  }
}

这为您的实现增加了额外的复杂性,但它也为您提供了您正在寻找的公共合同,以及与接口的兼容性。

于 2013-05-13T14:15:44.547 回答
0

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

接口编程的一般方式是您应该实现接口中描述的确切方法或属性。假设您有接口:

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

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

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

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

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

这是遵循LSV 原则

于 2013-05-13T14:16:52.820 回答