当我们在使用Visual Studio编写代码实现某个接口的时候,Visual Studio的智能提示就会提示我们要实现接口。点击该提示之后,可以看到两个选项,一个是实现该接口,另一个是显式的实现该接口。接下来,我们看看这两种实现接口的方式有什么不同之处。
当你创建一个类型时,公共语言运行时(Common Language Runtime, CLR)会为该类型创建并初始化一个方法表,在这个方法表中,该类型的所有方法都有一个对应的记录项。它包括类型自身定义的新方法和继承自基类的方法以及实现街口时由接口定义的方法。
比如:
public class ArticleService : IArticleService { public int Insert(Article a) { return - 1 ;} } public interface IArticleService { int Insert(Article a); }
接口IArticleService中定义的一个方法 int Insert(Article a); 如上述,上面的代码可以得出,CLR为其创建的方法表应该包含以下记录项:
1、 Object定义的所有虚实例方法。(Object是终极基类,C#中所有的类型都有隐式的继承自Object。)
2、 IArticleService接口定义的所有方法。
3、 ArticleService 类型引入的新方法。上面代码中int Insert(Article a)就是新引入的方法。甚至可以说它并不是在实现接口方法。
由于类型定义的Insert方法与它所实现的接口定义的方法具有完全相同的方法签名、返回类型以及可访问性,于是CLR便假设这个方法是对接口方法的一个实现。若该方法被标记为virtual ,CLR仍然会如此假设。
做出这些假设之后,CLR就是会成有关该类型的元数据,指明方法表中的两个方法共享同一个实现。这个两个方法是IArticleService.Insert(Article a)和Insert(Article a),前者为接口定义,后者是类型新引入的方法。在元数据中他们共享同一个实现。
public class Program { public static void Main() { ArticleService a = new ArticleService(); Console.WriteLine( a .Insert( new Article())); Console.WriteLine(((IArticleService) a ).Insert( new Article())); } }
这段代码的打印结果是
-1 |
-1 |
可以看出这个两个方法都调用同一个实现。这种实现接口的方式就叫做
隐式的实现接口。
还有一种实现接口的方式是显示的实现接口(Explicit Interface Method Implementation , EIMI)。现在我们来修改ArticleService对接口的实现。
public class ArticleService:IArticleService{public int Insert(Article a){ return - 1 ; }int IArticleService.Insert(Article a){ return 1 ; }}
在不改变Main方法的情况下,它的输出将会有所改变: 结果变为
-1 |
1 |
为什么会有这些改变呢?因为显式实现接口之后,CLR为类型生成元数据的时候,前面提到过的方法表中的那两个方法将会指向不同的实现。所以打印结果改变了。显式实现接口时要注意,显式实现接口方法是不能指定其可访问性的,CLR在编译类型的时候会自动给它加上private 。这是为防止类型的实例调用它,事实上它必须是私有的,否则实例调用就会出现混淆。要调用显式实现的接口方法,必须将类型强制转换成接口类型,才能调用这个方法。显式实现接口方法不能被标记为virtual , 所以也就不能被派生类重写,不能被派生类访问,不能被自身实例访问,这看起来都不像是这个类所拥有的方法。它看起来是把类类接口绑定在一起一样。