9

我听说在 Java 8 中可以灵活地在接口中定义函数。我认为我们可以在所有实现此类接口的类中使用此功能具有一些默认状态。

所以,我的问题是,截至今天,我们在 C# 中是否有任何此类功能?微软在这方面有什么计划吗?

4

5 回答 5

5

更新

默认接口方法是 C# 8 的计划功能

原始答案

C# 没有这个确切的功能,但扩展方法解决了与在 Java 中引入默认方法来解决的相同问题。

为了将类似 LINQ 的函数方法引入 Java 8 中的公共集合,语言设计者想要一种方法来向接口(如Iterable<>. 毕竟,.filter(a -> ...).map(a -> ...)语法比 更容易阅读map(filter(a ->...), a2 -> ...),如果他们只是添加实用程序方法,他们就必须这样做。然而,仅仅向接口添加方法签名将是一个重大更改,因为任何曾经实现该接口的人都会突然拥有在 Java 8 中构建的代码,除非他们实现了新方法。因此,他们开发了默认实现方法,以便将新方法放在现有接口上不会破坏现有代码。

几年前,C# 通过引入扩展方法解决了同样的问题。扩展方法并没有实际更改接口本身,而是使使用实用程序类中定义的方法(如.Where().Select()上的方法IEnumerable<>)变得容易,就好像它实际上在目标对象上一样。

对扩展方法和默认实现的约束使它们在范围上非常相似。每个都有一些优点和缺点,我不会在这里讨论,但本质上它们只是解决同一问题的两种不同方法。

因为它与您的具体问题有关:扩展方法的缺点之一是(静态的)它们破坏了面向对象代码的一些最佳实践:它们之间可能存在命名冲突,并且您不能覆盖例如,它们可靠。因此,通常最好避免使用它们,除非您遇到无法通过任何其他方式轻松解决的问题。如果您只是希望提供一个方法的默认实现,那么您通常最好使用基类,并期望人们扩展您的基类。

我想你会发现大多数 Java 专家都会对 Java 中的默认实现说同样的话。在 Java 8 之前没有引入它们,因为普遍的观点是接口用于定义事物能够做什么,而类则用于定义如何完成这些事情。当然,你总能找到一些聪明的人,他们认为一开始就没有充分的理由拥有接口. 但是,如果您使用接口,大概是因为您看到了在不提供实现细节的情况下定义合约的价值。引入默认实现是为了解决一个非常具体的向后兼容性问题,如果你能在一开始就避免这个问题,那么我看不出有什么好的理由使用它们。

扩展方法同时更危险且更强大,因此它们在向后兼容问题之外还有一些很好的用途,但它们仍应谨慎使用,并且仅在其他更面向对象的方法不起作用时才使用。

于 2016-12-21T04:07:51.947 回答
3

C# 中默认接口实现的官方语言提案记录在此:

https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md

它当前标记为“提案”状态。

话虽如此,它有许多非常强大的用例。目前,正如 Mass Torgerson 和 Dustin Campbell 在下面的视频中所表明的那样,它似乎很有可能获得批准。如果是这样,几乎可以肯定它与 C#8 一起发布。

https://channel9.msdn.com/Events/Build/2017/B8104

53:00 左右,讨论开始并展示了演示。

于 2017-05-14T02:05:28.463 回答
2

C# 8.0 将引入默认接口实现的新特性。当添加新方法以保持与接口的现有实现的兼容性时,这很有用。它还可以提供简单的默认实现,如下例所示:

public interface ILogger  
{
    void Log(LogLevel level, string message);

    void Log(LogLevel level, string format, params object[] arguments)
    {
        Log(level, string.Format(format, arguments));
    }
}

新的 C# 功能

于 2017-09-25T11:16:52.680 回答
1

我同意到目前为止评论中的陈述 - C# 不支持这一点。据我所知,没有计划在 C# 中支持这一点,也不应该支持。我不同意 Java 8 也包含这个特性。我认为它将接口和抽象基类混为一谈。正如@AntP 在评论中所说,接口应该是合同(而不是指定行为)。

以下是完成相同事情的两种可能的设计(对于仓促绘制的 UML 感到抱歉): 在此处输入图像描述

基本上,要点是您可以创建一个抽象基类,为所有子类添加默认实现,或者如果您正在尝试这样做,您可以为一些实现接口的子类创建一个基类。

显然其他设计是可能的,这个图主要是为了说明的目的。

于 2016-12-19T16:15:46.783 回答
1

C# 不支持这一点,但我不同意接口应该是合同而不是实现的评论。因为默认实现不是为了实现的麻袋,它是为了让客户端免于实现新更新的接口,如果他们不使用他们以前使用的新版本 api 中引入的新方法,就不让他们的旧冷中断.

java 8 实现中的默认方法确实有助于解决更新 api 后出现的实际问题。

于 2016-12-21T04:02:29.037 回答