为什么我不能这样实现一个接口?

12

可能是重复问题:
C#是否支持返回类型协变?

我不确定我是不是只是傻了……

如果我有一个接口:

public interface IMoop
{
    object Moop();
}

为什么我不能像这样实现它(我猜这会使用隐式协变?)

public class MoopImplementor : IMoop
{
    string Moop();
}

任何 MoopImplementor 的实例都符合 IMoop 指定的契约,所以这似乎应该没问题。

请启发我 :)

编辑:为了明确 - 由于实现类返回的东西继承自接口方法的返回类型 - 我认为这应该可以工作。具体来说,一个 string 是一个 object。(其他继承链也是如此)。


1
@Dave:编译器在这里很严格。你需要明确地让 Moop() 返回一个 object,否则你就没有实现接口。这不是问题,因为你可以像你正确地指出的那样,简单地从方法中返回一个 string - Niklas B.
1
从技术上讲,合同还允许我返回整数,而您的实现不允许。 - kailoon
2
是的,我明白这点。但为什么是这样的问题呢 :) - Dave Bish
1
@kailoon 不是的。这份合同允许您返回作为对象封装的整数,但不允许返回整数。它们是不同的。 - Chris Shain
2
关于你的编辑“我觉得这应该可以工作” - 我觉得人们应该给我免费的钱,但这并不意味着会发生。 - asawyer
显示剩余6条评论
5个回答

13

C#不支持用于接口实现或虚方法重写的返回类型协变。有关详细信息,请参见此问题:

C#是否支持返回类型协变?

截至C# 4,C#支持使用引用类型构造的接口和委托类型的泛型协变和逆变。

当将返回引用类型的方法转换为其返回类型兼容的委托类型时,C#确实支持返回类型协变。(同样,它支持参数类型逆变)。

如果您对此主题感兴趣,我已经写了很多篇文章,讨论了C#支持和不支持的各种版本的协变性。请参见:

https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/了解详情。


1
天啊,你没开玩笑吧——11篇关于方差的博客文章。我的下午就这么过去了 :) - Dave Bish

7

由于接口规定该方法必须返回一个object,因此string可以从object继承,但接口规定了返回更通用类型的方法。

不过要记住,你完全可以执行以下操作:

public object Moop()
{
    return "Some new string";
}

1
但是字符串是一个对象。 - Dave Bish
无论我在哪里使用它作为接口 - “string”或任何其他东西都将满足“成为对象”的合同。 - Dave Bish
1
@Dave:你的观点是无关紧要的。事实就是这样。你想表达什么? - Niklas B.
那么,这只是编译器的不灵活性吗?因为这就是问题的全部。 - Dave Bish
2
@NiklasB。Dave发布的问题是“为什么会这样”。我猜你的回答是“它就是这样”。对我来说,这听起来不像一个好答案。也许Jon Skeet会跟进一下,看看C#不允许这样做是否有原因。 - Naz
显示剩余9条评论

4
一个合理的解决方法:
public class MoopImplementor : IMoop {
  public string Moop() { ... }
  object IMoop.Moop() { return Moop(); }
}

这使得公共实现中的MoopImplementor可以拥有更准确的类型,同时仍然满足接口的要求。

这一直困扰着我,特别是 IEnumerable 等等。但我想我们必须做我们必须做的事情。 - leppie

3

您没有满足合约。但是,您可以通过使用泛型来实现:

public interface IMoop<T>
{
    T Moop();
}

public class MoopImplementor : IMoop<string>
{
    public string Moop() { return ""; }
}

@asawyer:赞一个,回答很好。 - Arian
@NiklasB。我同意,这是一件不同的事情。 - asawyer
抱歉 - 这不是问题。 - Dave Bish
1
@Dave,答案是你的实现没有满足接口的契约义务。请换一种方式实现。 - asawyer

2

来自C#语言规范:

13.4.4 接口映射

为了接口映射,当类成员A与接口成员B匹配时:

  • A和B都是方法,且A和B的名称、类型和形式参数列表相同

请注意,它没有提到继承或可转换性!返回类型必须相同。


虽然这很好,但它并没有提到背后的原因 :) - Niklas B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接