C# 8: 默认接口方法
翻譯自 John Demetriou 2018年8月4日 的文章 《C# 8: Default Interface Methods》[1]
C# 8 之前
今天我們來聊一聊默認(rèn)接口方法。聽起來真的很奇怪,不是嗎?接口僅用于定義契約。接口的實現(xiàn)類會擁有一組公共方法,不過實現(xiàn)類被賦予了以其自己的方式實現(xiàn)每個方法的自由。目前為止,如果我們還需要為這些方法中的一個或多個方法提供實現(xiàn),我們將使用繼承。
如果我們希望這個類不是實現(xiàn)所有方法,而只是實現(xiàn)其中的一個子集,我們可以將這些方法和類本身抽象(abstract)。
例如,我們不能這么寫:
interface IExample {void Ex1(); // 允許void Ex2() => Console.WriteLine("IExample.Ex2"); // 不允許(C# 8 以前) }我們不得不用下面的抽象類來替代:
abstract class ExampleBase {public abstract void Ex1();public void Ex2() => Console.WriteLine("ExampleBase.Ex2"); }不過還好,這已經(jīng)足夠滿足我們的大部分需求了。
C# 8 之后
那么,有什么改變嗎?為什么我們需要引入這個新特性?我們錯過了什么并且從未注意到我們錯過了什么?
菱形問題
由于菱形問題[2],C#(以及許多其他語言)不支持多重繼承。為了允許多重繼承,同時避免菱形問題,C# 8 引入了默認(rèn)接口方法。
從 C# 8 開始,使用默認(rèn)接口方法,您可以擁有一個接口定義,以及該定義中某些或所有方法的默認(rèn)實現(xiàn)。
interface IExample {void Ex1(); // 允許void Ex2() => Console.WriteLine("IExample.Ex2"); // 允許 }因此,現(xiàn)在您可以實現(xiàn)一個含有已實現(xiàn)方法的接口,并且可以避免希望從特定類(也包含通用方法)繼承的類中的代碼重復(fù)。
使用默認(rèn)接口方法,菱形問題并沒得到百分之百解決。當(dāng)一個類繼承自從第三個接口繼承而來的兩個接口,并且所有接口都實現(xiàn)了相同方法時,仍然可能發(fā)生這種情況。
在這種情況下,C# 編譯器將根據(jù)當(dāng)前上下文選擇調(diào)用適當(dāng)?shù)姆椒āH绻麩o法推斷出特定的哪一個,則會顯示編譯錯誤。
例如,假設(shè)我們有以下接口:
interface IA {void DoSomething(); }interface IB : IA {void DoSomething() => Console.WriteLine("I am Interface B"); }interface IC : IA {void DoSomething() => Console.WriteLine("I am Interface C"); }然后,我創(chuàng)建一個實現(xiàn)上述兩個接口的類?D,會引發(fā)一個編譯錯誤:
//編譯器提示:“D”未實現(xiàn)接口成員“IA.DoSomething()” public class D : IB, IC { }但是,如果類?D?實現(xiàn)它自己版本的?DoSomething?方法,那么編譯器將知道調(diào)用哪個方法:
public class D : IB, IC {public void DoSomething() => Console.WriteLine("I am Class D"); }若 Main 方法代碼如下:
static void Main() {var x = new D();x.DoSomething();Console.ReadKey(); }運行程序,控制臺窗口輸出:I am Class D。
其他益處
使用方法的默認(rèn)接口實現(xiàn),API 提供者可以擴展現(xiàn)有接口而不破壞遺留代碼的任何部分。
Trait 模式
譯者注:
在計算機編程中,特征(Trait)是面向?qū)ο缶幊讨惺褂玫囊粋€概念,它表示可用于擴展類的功能的一組方法。[3]
Trait 模式大體上就是多個類需要的一組方法。
在此之前,C# 中的 Trait 模式是使用抽象類實現(xiàn)的。但是由于多重繼承不可用,實現(xiàn) Trait 模式變得非常棘手,所以大多數(shù)人要么避開它,要么迷失在一個巨大的繼承鏈中。
不過,在接口中使用默認(rèn)方法實現(xiàn),這將發(fā)生改變。我們可以通過在接口中使用默認(rèn)接口方法實現(xiàn),提供一組需要類擁有的方法,然后讓這些類繼承此接口。
當(dāng)然,任何一個類都可以用它們自己的實現(xiàn)覆蓋這些方法,但是以防它們不希望這么做,我們?yōu)樗鼈兲峁┝艘唤M默認(rèn)的實現(xiàn)。
以下為譯者補充
接口中的具體方法
默認(rèn)接口方法的最簡單形式是在接口中聲明具體方法,該方法是具有主體部分的方法。
interface IA {void M() { Console.WriteLine("IA.M"); } }實現(xiàn)此接口的類不必實現(xiàn)其具體方法。
class C : IA { } // OKstatic void Main() {IA i = new C();i.M(); // 輸出 "IA.M" }類?C?中?IA.M?的最終替代是在?IA?中聲明的具體方法 “M” 。
請注意,類只能實現(xiàn)接口,而不會從接口繼承成員:
但如果實現(xiàn)此接口的類也實現(xiàn)了具體方法,則同一般的接口含義是一樣的:
class C : IA {public void M() { Console.WriteLine("C.M"); } }static void Main() {IA i = new C();i.M(); // 輸出 "C.M" }相關(guān)鏈接:
https://www.devsanon.com/c/c-8-default-interface-methods/?C# 8: Default Interface Methods???
https://mp.weixin.qq.com/s/EZ_jIjT6hYFrhbJ9BZ7Amw?菱形問題???
https://en.wikipedia.org/wiki/Trait_(computer_programming)?Trait???
作者 :John Demetriou?
譯者 :技術(shù)譯民?
出品 :技術(shù)譯站(https://ITTranslator.cn/)
總結(jié)
以上是生活随笔為你收集整理的C# 8: 默认接口方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#9引入的自定义类型record
- 下一篇: C# 中的只读结构体(readonly