【所见即所得】抽象类、接口的一点费解
一、问题引入:
看一些开源项目源码的时候,经常看到如下的结构设计:
我表示很费解。
二、问题分析:
为了分析问题,我写了几个测试的类和接口,如下:
接口:
public interface A { string Test1(); void Test2(); }
抽象类:
public abstract class B :A{ #region A 成员 public virtual string Test1() { Console.WriteLine("abstract B Test1"); return "B Test1"; } public virtual void Test2() { Console.WriteLine("abstract B Test2"); } #endregion }
同时继承抽象类和实现接口的具体类:
public class C :B,A{ }
只继承抽象类的具体类:
public class D :B{ }
测试也下各种用法:
A a1 = new C(); A a2 = new D(); B b1 = new C(); B b2 = new D(); a1.Test1(); a2.Test1(); Console.WriteLine(a1.GetType().GetInterfaces()[0]); Console.WriteLine(a2.GetType().GetInterfaces()[0]); Console.WriteLine(a1.GetType().BaseType); Console.WriteLine(a2.GetType().BaseType); Console.WriteLine("-----------------------------------------------"); Console.WriteLine(b1.GetType().GetInterfaces()[0]); Console.WriteLine(b2.GetType().GetInterfaces()[0]); Console.WriteLine(b1.GetType().BaseType); Console.WriteLine(b2.GetType().BaseType);
结果如下:
也就是这两个具体类从表面上(运行结果)看没有什么不同。
我仔细的查看了一下他们的IL代码:
.class public auto ansi beforefieldinit D extends FMS_Refacting.interfaceAndabsctract.B { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void FMS_Refacting.interfaceAndabsctract.B::.ctor() L_0006: ret } }
.class public auto ansi beforefieldinit C extends FMS_Refacting.interfaceAndabsctract.B
implements FMS_Refacting.interfaceAndabsctract.A
{ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void FMS_Refacting.interfaceAndabsctract.B::.ctor() L_0006: ret } }
唯一的不同就是红色部分标出。但这不会影响什么,因为根据继承的定义,D是通过B来implements了A的,这种传递性和上面的没有什么区别。所以从这里看也没什么不同。
也就是说,这个两种形式是一样的!!!
我们知道:
接口:是包含一组虚方法的抽象类型,其中每一种方法都有其名称、参数和返回值。接口方法不能包含任何实现,CLR允许接口可以包含事件、属性、索引器、静态方法、静态字段、静态构造函数以及常数。但是注意:C#中不能包含任何静态成员。一个类可以实现多个接口,当一个类继承某个接口时,它不仅要实现该接口定义的所有方法,还要实现该接口从其他接口中继承的所有方法。
抽象类:提供多个派生类共享基类的公共定义,它既可以提供抽象方法,也可以提供非抽象方法。抽象类不能实例化,必须通过继承由派生类实现其抽象方法,因此对抽象类不能使用new关键字,也不能被密封。如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。另外,实现抽象方法由override方法来实现。
抽象类和接口比起来,有一个好处,就是某些函数可以实现具体的方法,而并不一定是声明抽象的方法,而接口只能声明抽象方法(并且强制子类实现),所以用一个抽象类来实现某个接口可以实现一些通用的方法,而这些具体实现的方法里还可以调用抽象方法,所以减少了子类中的重复代码。
所以,D的继承形式我觉着是比较常用的,但是为什么又出现C继承形式了呢?我的猜想:
- 1、应该是框架上的需要便于扩展?
- 2、与设计模式有关?
- 3、美观?
三、最后
我还是不能确定为什么要这么设计,有什么特殊的原因是我没有想到的么?如果你知道请告诉我,我也会一直的寻找原因。不胜感激。
作者:付之一笑
出处:博客园——付之一笑
希望对您有帮助,您的关注和推荐是对我最大的支持。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。