一、多态性
除了使用继承使用多态性,还能通过接口使用它。与抽象类不一样的是,接口不包含任何实现。
二、接口的实现
1.显示
使用显示的方法实现接口,只能通过接口本身调用它,所以,最典型的做法是将对象转型为接口。
internal interface IPerson { string FullName { get; } } public class Contact : IPerson { public string FirstName { get; set; } public string LastName { get; set; } string IPerson.FullName { get { return FirstName + " " + LastName; } } }
Contact contact = new Contact(); contact.FirstName = "FirstName"; contact.LastName = "LastName"; //Contact 不包含FullName的定义 Console.WriteLine(contact.FullName); Console.WriteLine(((IPerson) contact).FullName);
2.隐式
上面代码中FullName前面不加IPerson则为隐式实现。要隐式实现一个成员,只要类成员的签名和接口成员的前面相符即可。
由于成员是像类其他成员一样声明,所以可以在代码中直接调用隐式实现的成员。 Console.WriteLine(contact.FullName); 就不会报错。
隐式实现必须是public,显示实现是不允许加修饰符的。此外,在隐式实现中virtual是可选的(如果派生类可以重写实现就加上,反之,不加上),override是不允许的(由于成员的接口不包含实现,所以override没有意义)。
3.显示实现接口与隐式实现接口比较
区别主要在于从实现接口类外部分可访问性。
一下是基本的设计原则,帮助你选择是显示还是隐式实现:
1.成员是不是类核心的功能?
如果不是就显示实现,反之,隐式实现。
2.接口成员名作为类成员是否恰当?
简单说就是接口方法前面在实现类中是否会引起歧义,如果会则显示实现,不会则可以隐式实现。
3.是否已有一个同名的类成员?
有就显示实现,没有则可以隐式实现。
三、接口继承
一个接口可以从另一个接口派生,派生的接口将继承“基接口”的所有成员。
interface IBase { void Get(); } internal interface IBaseExpand : IBase { void GetByName(string name); } public class ServiceClass : IBaseExpand { public void Get() { } public void GetByName(string name) { } }
这里有意思的是,如果Get()是显示实现的话,那么必须使用IBase.Get()
多接口继承
接口上的扩展方法
通过接口实现多重继承
四、版本控制
如果我们的组件是给其他人用的话,在创建一个新版本时,不应改动接口。
一般是新建一个继承原有接口的新接口。
五、接口和类比较
接口引入了另一个类别的数据类型。是少数不对基类System.Object进行扩展的类型之一(还有指针类型和类型参数类型)。
抽象类 | 接口 |
1.不能脱离它的派生类来实例化,构造器只能由它的派生类调用。 2.定义了基类必须实现的抽象成员签名。 3.扩展性比接口好,不会破坏任何版本兼容性。 4.可以包含存储在字段的数据。 5.允许包含实现的(virtual)成员,所以能为派生类提供一个默认的实现。 6.从一个抽象类派生,会用掉类唯一的一个基类型选项(单一继承) |
1.不能实例化。 2.接口所有成员必须在基类中实现。 3.会破坏版本兼容性。 4.不能存储任何数据。只能在派生类中指定字段(解决这个问题的方法是定义属性,但不能包括实现)。 5.所有成员自动成为virtual成员,但不包括任何实现。 6.虽然不允许存在默认实现,但实现接口的类可以继续相互派生。 |