探索 C# 10 的 static abstract 接口成員
引例
考慮一種情況。我們總是喜歡對帶有加減乘除運算符的對象完成一些基本的操作和行為,但 int
、double
甚至 nint
這樣的數(shù)據(jù)類型在 C# 里都帶有 +
運算符,如果我們嘗試著泛化執(zhí)行邏輯,以前的 C# 還不能完成這樣的任務。C# 10 開始,我們可以使用接口來完成。
首先我們讓所有這樣的數(shù)據(jù)類型支持 INumber<T>
接口:
然后,我們直接對這樣的接口來完成操作:
在這樣的代碼里,我們用到了 Default
屬性和 +
運算符。C# 以前的接口都無法對這樣的成員完成書寫和實現(xiàn),現(xiàn)在有了這樣的語法后,我們就可以完美支持這一點了。
特別注意語法
T.Default
。我們使用泛型參數(shù)名后直接跟上Default
的方式來表達我要獲取的是T
這個數(shù)據(jù)類型下的Default
屬性成員。為什么可以這么寫呢?因為T
參數(shù)實現(xiàn)了INumber<T>
接口,而這個接口里自帶Default
成員。因此,我寫T.Default
就意味著我直接取這個屬性的值。
語法
我們只需要在接口里的、你需要的必須讓類型實現(xiàn)的成員前面使用 static abstract
修飾符即可。注意,abstract
此時是不可缺少的。雖然我們知道 C# 里的接口默認以 public abstract
作為抽象的基本修飾符,但在這個特性里,我們不得不追加 static abstract
這個修飾符組合來同時表達它是靜態(tài)成員,且必須在實現(xiàn)類型里完成對這個成員的實現(xiàn)。
稍微注意一點。我們?yōu)榱俗尫盒蛥?shù)類型可以使用運算符操作,我們需要追加一個看起來好像沒用、但實際上很有用的泛型約束模式:where T : INumber<T>
。是的,INumber<T>
接口是它自己,而這個泛型約束表示當前泛型參數(shù)類型 T
必須也實現(xiàn)它自己這個類型。這不是廢話嗎,難不成還可以不實現(xiàn)?
是的,它完全可以不實現(xiàn),甚至是毫不相關的情況。不妨思考一下,我們在使用 IEnumerable<T>
接口的時候,我們自定義的集合數(shù)據(jù)類型(比如假定叫 Class
因為 Class
可能會封裝上一個比較小的集合類型的數(shù)據(jù)作為底層的數(shù)據(jù)類型實現(xiàn),比如我里面有一個 int[]
,那么 GetEnumerator
我恰好就直接把這個 int[]
類型的底層字段拿來取迭代器。這個時候,我們實現(xiàn)接口就應該是 IEnumerable<int>
。可以看到,Class
類型的這個 Class
此時是和 IEnumerable<int>
里的這個 int
是完全不一樣的兩個數(shù)據(jù)類型。
而我們在為了使用泛型參數(shù)類型的運算符抽象的時候,我們寫上 where T : INumber<T>
的目的純粹就是為了表達“我自己這個類型就是實現(xiàn)這個接口的泛型參數(shù)”。如果沒有這層約束的話,那么我的泛型參數(shù) T
就可能和接口本身完全沒有關系。想一想我們 C# 最開始運算符重載的實現(xiàn)規(guī)則是不是有一條這樣的話:我們自定義的運算符重載,傳入的運算符參數(shù)必須至少有一個和這個類型本身一致,或為它的可空類型(即 T?
,如果這里的 T
是值類型的話)。
是的,如果我們不使用泛型參數(shù)的“自實現(xiàn)”約束的話,這個參數(shù)就可能和接口無關,因此不符合 C# 基本實現(xiàn)的規(guī)則,達不到約束的目的。因此 C# 10 規(guī)定,你必須得讓泛型參數(shù)帶上“自實現(xiàn)”的約束,才可以使用對泛型參數(shù)的運算符重載的抽象化行為。
有了這層約束后,接口就顯得非常容易看了。我們再次把剛才的 INumber<T>
接口照搬過來:
這一次你再看看,是不是就沒問題了?
我們現(xiàn)在來看一下完整的示例,給大家演示一下如何使用接口里的靜態(tài)抽象成員這一特性。
看得懂了嗎?
支持的成員
支持 static abstract
的成員,除了字段、構造器(本來接口就沒有實例構造器一說)和索引器(索引器本身確實就沒有 static
一說)以外,別的都可以:
屬性
事件
方法
運算符
類型轉換
用起來吧!
靜態(tài)抽象成員的顯式接口實現(xiàn)
和實例成員的實現(xiàn)方式一樣,如果你不得不隱藏接口成員,你可以使用基本的顯式接口實現(xiàn)的模式來完成,不過要記得帶上 static
關鍵字。
INumber<A>.operator +