爲何用這種方式設計C#? 函數
據我瞭解,接口僅描述行爲,而且其目的是描述實現實現某些行爲的接口的類的合同義務。 spa
若是類但願以共享方法實現這種行爲,爲何不呢? .net
這是我想到的一個例子: 設計
// These items will be displayed in a list on the screen. public interface IListItem { string ScreenName(); ... } public class Animal: IListItem { // All animals will be called "Animal". public static string ScreenName() { return "Animal"; } .... } public class Person: IListItem { private string name; // All persons will be called by their individual names. public string ScreenName() { return name; } .... }
就接口表示「合同」而言,靜態類實現接口彷佛很合理。 code
上述論點彷佛都錯過了關於合同的這一點。 xml
大多數人彷佛忘記了,在OOP中,類也是對象,所以它們具備消息,因爲某種緣由,c#將其稱爲「靜態方法」。 實例對象和類對象之間存在差別的事實僅代表該語言存在缺陷或不足。 雖然對C#持樂觀態度... 對象
好的,這是須要「類型方法」的示例。 我正在基於某些源XML建立一組類之一。 因此我有一個 繼承
static public bool IsHandled(XElement xml)
在每一個類上依次調用的函數。 接口
該函數應該是靜態的,不然咱們會浪費時間建立不合適的對象。 正如@Ian Boyde指出的那樣,能夠在工廠類中完成此操做,但這隻會增長複雜性。 開發
最好將其添加到接口以強制類實現者實現它。 這不會形成很大的開銷-這只是編譯/連接時間檢查,不會影響vtable。
可是,這也是一個至關小的改進。 因爲該方法是靜態的,所以做爲調用方的我必須顯式調用它,所以,若是未實現,則會當即產生編譯錯誤。 容許在接口上指定該錯誤將意味着此錯誤在開發週期的早期出現,可是與其餘接口損壞問題相比,這是微不足道的。
所以,這是一個次要的潛在功能,總的來講最好將其遺漏。
關於在非泛型上下文中使用的靜態方法,我贊成在接口中容許它們沒有太大意義,由於若是您仍然引用了該接口,則將沒法調用它們。 可是,經過在非多態上下文中使用接口而不是在通用上下文中建立接口,在語言設計中存在一個根本性的漏洞。 在這種狀況下,接口根本不是接口,而是約束。 因爲C#在接口外部沒有約束的概念,所以缺乏實質性的功能。 例子:
T SumElements<T>(T initVal, T[] values) { foreach (var v in values) { initVal += v; } }
這裏沒有多態性,泛型使用對象的實際類型並調用+ =運算符,但這失敗了,由於沒法肯定該運算符是否存在。 一種簡單的解決方案是在約束中指定它。 簡單的解決方案是不可能的,由於運算符是靜態的,而且靜態方法不能在接口中,而且(這裏是問題)約束表示爲接口。
C#須要的是真正的約束類型,全部接口也將是約束,可是並不是全部約束都將是接口,那麼您能夠這樣作:
constraint CHasPlusEquals { static CHasPlusEquals operator + (CHasPlusEquals a, CHasPlusEquals b); } T SumElements<T>(T initVal, T[] values) where T : CHasPlusEquals { foreach (var v in values) { initVal += v; } }
關於爲全部要實現的數字類型實現IArithmetic已有不少討論,可是因爲效率不是多態構造,所以存在效率問題,所以,使CArithmetic約束能夠解決該問題。
由於接口處於繼承結構中,因此靜態方法不能很好地繼承。