zoukankan      html  css  js  c++  java
  • C# 接口

    我在网上查了很多关于C#接口的资料,这篇文章是我从网上复制下来的,我觉的它写的很好,我从中学到很多,使我对接口的认识 更进了一步。我本来想写一篇属于自己的C#接口的个人认识,但在高手面前还是不要帮门弄斧,后来就决定将这篇文章写在博客里,和大家一起分享知识和学习。希望这篇文章可以帮助任何一个学习C#接口的IT人员。谢谢

    1、公有方法实现接口方法

    尽管C#在定义接口时不用指明接口方法的访问控制方式,但默认接口方法均为public型(这可以从反编译的IL代码中看到)。下面是使用Reflector查看的接口IL代码

    .class private interface abstract auto ansi IControl

    {

       .method public hidebysig newslot abstract virtual instance void Paint() cil managed

       {

       }

    }

     

    实现接口的类需要实现所有接口方法。通常情况下,接口的实现方法也为public型。如下案例:

    using System ;

    interface IControl 

    {

       void Paint();

    }

    public class EditBox: IControl 

    {

       public void Paint() 

       {

          Console.WriteLine("Pain method is called!");

       }

    }

    class Test 

    {

       static void Main() 

       {

          EditBox editbox = new EditBox(); 

          editbox.Paint();

          ((IControl)editbox).Paint();

       }

    }

    程序的执行结果为:

    Pain method is called!

    Pain method is called!

    接口就好像是关系型数据库中的一对多表,一个接口对应多个接口方法,每个接口方法又对应虚拟方法表(VMT)中的某个公有或私有方法。上面代码在内存中的镜像可由下图描述:

     

    从图中我们可以看到直接对Paint方法的调用以及通过接口对Paint方法的调用。可见通过接口对方法进行调用需要多出一道转换工作,因此执行效率不如直接调用。

    2、私有方法不能实现接口方法

    如果想将接口方法直接实现为私有方法是办不到的。下面的EditBox的代码中Paint方法没有特殊说明,默认为private,导致代码无法执行:

    using System ;

    interface IControl 

    {

       void Paint();

    }

    public class EditBox: IControl 

    {

       void Paint() 

       {

          Console.WriteLine("Pain method is called!");

       }

       public void ShowPaint()

       {

          this.Paint();

          ((IControl)this).Paint();

       }

    }

    class Test 

    {

       static void Main() 

       {

          EditBox editbox = new EditBox(); 

          editbox.ShowPaint();

       }

    }

    程序在编译时将显示如下编译错误:““EditBox”不会实现接口成员“IControl.Paint()”。“EditBox.Paint()”或者是静态、非公共的,或者有错误的返回类型。”

    为什么会这样呢?如图:

     

    这是由于接口规范中的方法默认的访问权限是public,而类中的默认访问权限是default,也就是说private,因此导致权限范围收缩,两者权限并不相同,所以必须将类的权限调整为public才可以使上面的代码得以执行。

    3、实现专门的接口方法(1)

    代码如下:

    using System ;

    interface IControl 

    {

       void Paint();

    }

    public class EditBox: IControl 

    {

       void Paint()

       {

          Console.WriteLine("Pain method is called!");

       }

       void IControl.Paint() 

       {

          Console.WriteLine("IControl.Pain method is called!");

       }

       public void ShowPaint()

       {

          this.Paint();

          ((IControl)this).Paint();

       }

    }

    class Test 

    {

       static void Main() 

       {

          EditBox editbox = new EditBox(); 

          editbox.ShowPaint();

          //editbox.Paint();

          ((IControl)editbox).Paint();

       }

    }

    EditBox类拥有一私有Paint方法,但这并不是接口方法的实现(上例已经分析过)。EditBox类中还包含了一“void IControl.Paint()”方法, 是该方法复写了接口的Paint方法,该方法是私有的(通过IL代码可以看出)。

    注意:“void IControl.Paint()”前不能加任何的修饰限定符号,诸如public、private等,这在C#的语法中是不允许的。该方法反编译得到的IL代码如下:

    .class public auto ansi beforefieldinit EditBox

          extends object

          implements IControl

    {

          .......

          .method private hidebysig newslot virtual final instance void IControl.Paint() cil managed

          {

                .override IControl::Paint

          }

    }

    程序运行时内存中的镜像可简化表示为:

     

    程序执行结果如下:

    Pain method is called!

    IControl.Pain method is called!

    IControl.Pain method is called!

    我们之所以可以通过((IControl)editbox).Paint()方法访问到代码是因为接口方法Paint是公有的。但是我们不能通过editbox.Paint()方法访问到代码是因为EditBox的Paint方法是私有的。 在EditBox内部,通过ShowPaint方法可以同时访问私有的Paint方法与接口IControl.Paint方法。

    4、实现专门的接口方法(2)

    如果EditBox中的Pait方法为公有并且同时提供了IControl.Paint方法,程序将是如何运行的呢?代码如下:

    using System ;

    interface IControl 

    {

       void Paint();

    }

    public class EditBox: IControl 

    {

       public void Paint()

       {

          Console.WriteLine("Pain method is called!");

       }

       void IControl.Paint()

       {

          Console.WriteLine("IControl.Pain method is called!");

       }

    }

    class Test 

    {

       static void Main() 

       {

          EditBox editbox = new EditBox(); 

          editbox.Paint();

          ((IControl)editbox).Paint();

       }

    }

    程序执行结果如下:

    Pain method is called!

    IControl.Pain method is called!

    程序执行时内存布局如下:

     

    可见,EditBox中公有的Paint方法并不是接口实现方法,真正的接口实现方法是IControl.Paint,这将导致editbox.Paint()方法与((IControl)editbox).Paint()的执行结果并不一样。

    5、结论

    接口方法的实现通常是通过类中的公有方法实现的;

    在一些特殊情况下(代码隐藏、一个类实现的两个接口具有相同的接口方法等),需要专门实现某个接口的方法。

     

     

     

  • 相关阅读:
    ubuntu之路——day8.4 Adam自适应矩估计算法
    ubuntu之路——day8.3 RMSprop
    ubuntu之路——day8.2 深度学习优化算法之指数加权平均与偏差修正,以及基于指数加权移动平均法的动量梯度下降法
    ubuntu之路——day8.1 深度学习优化算法之mini-batch梯度下降法
    ubuntu之路——day7.4 梯度爆炸和梯度消失、初始化权重、梯度的数值逼近和梯度检验
    redis作为mysql的缓存服务器(读写分离)
    阿里云服务器上配置并使用: PHP + Redis + Mysql 从配置到使用
    小程序开发测试教程
    使用PHP并发执行任务–curl_multi应用
    PHP返回变量或数组的字符串表示:var_export()
  • 原文地址:https://www.cnblogs.com/wuzehao/p/2695400.html
Copyright © 2011-2022 走看看