介面基礎知識
介面的功能稱為功能契約。這意味著它宣告瞭屬性和方法,但它沒有實現它們。
所以不像類介面:
- 無法例項化
- 不能有任何功能
- 只能包含方法* (屬性和事件是內部方法)
- 繼承介面稱為實現
- 你可以從 1 個類繼承,但可以實現多個介面
public interface ICanDoThis{
void TheThingICanDo();
int SomeValueProperty { get; set; }
}
需要注意的事項:
I
字首是用於介面的命名約定。- 函式體替換為分號“;”。
- 也允許屬性,因為在內部它們也是方法
public class MyClass : ICanDoThis {
public void TheThingICanDo(){
// do the thing
}
public int SomeValueProperty { get; set; }
public int SomeValueNotImplemtingAnything { get; set; }
}
。
ICanDoThis obj = new MyClass();
// ok
obj.TheThingICanDo();
// ok
obj.SomeValueProperty = 5;
// Error, this member doesn't exist in the interface
obj.SomeValueNotImplemtingAnything = 5;
// in order to access the property in the class you must "down cast" it
((MyClass)obj).SomeValueNotImplemtingAnything = 5; // ok
當你使用 WinForms 或 WPF 等 UI 框架時,這尤其有用,因為必須從基類繼承以建立使用者控制元件,並且你無法通過不同的控制元件型別建立抽象。一個例子?接下來:
public class MyTextBlock : TextBlock {
public void SetText(string str){
this.Text = str;
}
}
public class MyButton : Button {
public void SetText(string str){
this.Content = str;
}
}
提出的問題是兩者都包含一些文字的概念,但屬性名稱不同。並且你無法建立建立*抽象基類,*因為它們具有對 2 個不同類的強制繼承。介面可以緩解這種情況
public interface ITextControl{
void SetText(string str);
}
public class MyTextBlock : TextBlock, ITextControl {
public void SetText(string str){
this.Text = str;
}
}
public class MyButton : Button, ITextControl {
public void SetText(string str){
this.Content = str;
}
public int Clicks { get; set; }
}
現在 MyButton 和 MyTextBlock 可以互換。
var controls = new List<ITextControls>{
new MyTextBlock(),
new MyButton()
};
foreach(var ctrl in controls){
ctrl.SetText("This text will be applied to both controls despite them being different");
// Compiler Error, no such member in interface
ctrl.Clicks = 0;
// Runtime Error because 1 class is in fact not a button which makes this cast invalid
((MyButton)ctrl).Clicks = 0;
/* the solution is to check the type first.
This is usually considered bad practice since
it's a symptom of poor abstraction */
var button = ctrl as MyButton;
if(button != null)
button.Clicks = 0; // no errors
}