一、问题引入:
看一些开源项目源码的时候,经常看到如下的结构设计:
我表示很费解。
二、问题分析:
为了分析问题,我写了几个测试的类和接口,如下:
接口:
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、美观?
三、最后
我还是不能确定为什么要这么设计,有什么特殊的原因是我没有想到的么?如果你知道请告诉我,我也会一直的寻找原因。不胜感激。


