《Effective C#》读书笔记——条目23:理解接口方法和虚方法的区别<使用C#表达设计>
2013-01-16 21:25
921 查看
实现和覆写虚方法的区别:接口中声明的成员默认不是虚方法。派生类不能覆写基类中实现的接口成员。接口可以被显式实现,这会使针对该类的公有成员隐藏起来。接口与虚方法的概念不同,用法也不同。
运行输出:
我们发现,将MyDerivedClass的实例做了转换之后,调用Message()方法变成了该类基类Class的Message()方法——有时候我们常常需要创建接口,然后在基类中实现它们,并且在派生类中更改它们的实现,这时候我们该怎么办呢?这时候有两种办法可供选择。
运行输出:
运行输出:
运行输出:
实现接口拥有的选择要比创建和覆写虚函数多。我们可以为类层次创建密封类(sealed)的实现、虚实现或者抽象实现。我们还可以创建密封的实现,并在实现接口的方法中提供虚方法调用。我们也可以决定派生类应该如何及何时修改基类中实现的接口成员的默认行为。接口不是虚方法,而是一个单独的契约。
改变从基类继承的接口在派生类中的行为
我们来看一个简单的例子:interface IMsg { void Message(); } public class MyClass : IMsg { public void Message() { Console.WriteLine("MyClass"); } } public class MyDerivedClass : MyClass { public new void Message() { Console.WriteLine("MyDerivedClass"); } } public class EffectiveCSharp { public static void Main(string[] args) { MyDerivedClass d = new MyDerivedClass(); d.Message(); IMsg m = d as IMsg; m.Message(); Console.Read(); } }
运行输出:
我们发现,将MyDerivedClass的实例做了转换之后,调用Message()方法变成了该类基类Class的Message()方法——有时候我们常常需要创建接口,然后在基类中实现它们,并且在派生类中更改它们的实现,这时候我们该怎么办呢?这时候有两种办法可供选择。
1.将实现接口的基类中实现的接口成员定义成:virtual,并在派生类中override
interface IMsg { void Message(); } public class MyClass : IMsg { public virtual void Message() { Console.WriteLine("MyClass"); } } public class MyDerivedClass : MyClass { public override void Message() { Console.WriteLine("MyDerivedClass"); } } public class EffectiveCSharp { public static void Main(string[] args) { MyDerivedClass d = new MyDerivedClass(); d.Message(); IMsg m = d as IMsg; m.Message(); Console.Read(); } }
运行输出:
2.将实现接口的基类定义成抽象类,并将实现的接口成员定义为抽象成员
我们同时可以将派生类的重写方法定义成密封的防止其派生类再重写该方法:interface IMsg { void Message(); } public abstract class MyClass : IMsg { public abstract void Message(); } public class MyDerivedClass : MyClass { public sealed override void Message() { Console.WriteLine("MyDerivedClass"); } } public class EffectiveCSharp { public static void Main(string[] args) { MyDerivedClass d = new MyDerivedClass(); d.Message(); IMsg m = d as IMsg; m.Message(); MyClass c = (MyClass)m; c.Message(); Console.Read(); } }
运行输出:
派生类继承基类中接口的实现
其实派生类可以从基类中继承基类对接口的实现,因为派生类可以把该接口的声明成为其契约的一部分,即使它并没有实现任何该接口中成员的实现,只要类的某个公开可访问的方法与接口的签名相匹配,那么契约的条件即可满足,不过这种方法无法使用显示接口实现。例如下面的示例:interface IMsg { void Message(); } public abstract class MyClass : IMsg { public virtual void Message() { Console.WriteLine("MyClass"); } } public class MyDerivedClass : MyClass,IMsg { } public class EffectiveCSharp { public static void Main(string[] args) { MyDerivedClass d = new MyDerivedClass(); d.Message(); IMsg m = d as IMsg; m.Message(); MyClass c = (MyClass)m; c.Message(); Console.Read(); } }
运行输出:
小节
实现接口拥有的选择要比创建和覆写虚函数多。我们可以为类层次创建密封类(sealed)的实现、虚实现或者抽象实现。我们还可以创建密封的实现,并在实现接口的方法中提供虚方法调用。我们也可以决定派生类应该如何及何时修改基类中实现的接口成员的默认行为。接口不是虚方法,而是一个单独的契约。
相关文章推荐
- 《Effective C#》读书笔记——条目22:通过定义并实现接口替代继承<使用C#表达设计>
- 《Effective C#》读书笔记——条目28:提供粗粒度的互联网API<使用C#表达设计>
- 《Effective C#》读书笔记——条目26:避免返回对内部类对象的引用<使用C#表达设计>
- 《Effective C#》读书笔记——条目25:用事件模式实现通知<使用C#表达设计>
- 《Effective C#》读书笔记——条目27:让类型支持序列化<使用C#表达设计>
- 《Effective C#》读书笔记——条目21:限制类型的可见性<使用C#表达设计>
- 《Effective C#》读书笔记——条目11:理解短小方法的优势<C#语言习惯>
- 《Effective C#》读书笔记——条目24:用委托实现回调<使用C#表达设计>
- 《Effective C#》读书笔记——条目1:使用属性而不是可访问的数据成员<C#语言习惯>
- 《Effective C#》读书笔记——条目5:为类型提供ToString()方法<C#语言习惯>
- 《Effective C#》读书笔记——条目10:使用可选参数减少方法重载的数量<C#语言习惯>
- 《Effective C#》读书笔记——条目6:理解几个等同性判断之间的关系<C#语言习惯>
- 《Effective C#》读书笔记——条目3:推荐使用is或as而不是强制转换类型<C#语言习惯>
- 深入理解 c# 第一章 使用扩展方法对 List<Product> 排序
- 《Effective C#》读书笔记——条目2:用运行时常量而不是编译期常量<C#语言习惯>
- 《Effective C#》读书笔记——条目4:使用Conditional特性而不是#if条件编译<C#语言习惯>
- 《Effective C#》读书笔记——条目8:推荐使用查询语法而不是循环<C#语言习惯>
- [C#]泛型与非泛型集合类的区别及使用例程,包括ArrayList,Hashtable,List<T>,Dictionary<Tkey,Tvalue>,SortedList<Tkey,Tvalue>,
- 深入理解 c# 第五章 匿名方法用于Action<T>委托类型 反转字符 求平方根 求平均数
- c#打包文件解压缩 C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法 一个简单例子理解C#的协变和逆变 对于过长字符串的大小比对