界面基础知识
接口的功能称为功能契约。这意味着它声明了属性和方法,但它没有实现它们。
所以不像类接口:
- 无法实例化
- 不能有任何功能
- 只能包含方法* (属性和事件是内部方法)
- 继承接口称为实现
- 你可以从 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
}