• CLR via C#(17)--接口


    CLR不允许继承多个基类,但是可以继承多个接口。凡是能使用具名接口类型的实例的地方,都能使用实现了接口的一个类型的实例。 接口是对一组方法签名进行了统一命名,但不提供任何实现,而具体类则必须为继承的全部接口提供实现。

    1. 定义接口

    接口是用interface关键字定义对一组方法签名,接口名称一般以字母I开头;而且还可以为接口定义事件、索引器和属性,但禁止定义构造器和实例字段,也不能构造任何静态成员。例如:

    public interface IShout
    {
        public IShout();//×Error Interfaces cannot contain constructors 
        static void Shout1();//×Error The modifier 'static' is not valid for this item 
        void Shout();
        string Name { get; set; }

    2. 接口方法

    具体的类继承接口后要为接口中定义的方法提供实现。我们首先定义一个接口,然后再定义类来实现该接口。

    public interface IIntroduce
         {
             void Shout();
             void Description();
         } 

    接口方法,即具体类中实现接口中定义的方法,它的实现要注意几点:

    • 接口方法必须是Public;
    • CLR要求将接口方法标记为virtual,否则编译器会自动标记为virtual和sealed。

    public class Animal : IIntroduce
        {
            public void Shout()                     //接口方法为标记为virtual 
            {
                Console.WriteLine("Animal Shout.");
            }
            public virtual void Description()  //接口方法标记为virtual 
            {
                Console.WriteLine("Animal Description.");
            }
        }

    查看IL代码:

       clip_image004

    clip_image006

    • 派生类可以使用New关键字为接口提供自己的实现。

    public class Dog : Animal
       {
           public override void Description()//重写基类的接口方法 
           {
               Console.WriteLine("Dog Description!");
           }
       }

       public class Cat : Animal, IIntroduce
       {
           public override void Description()//重写基类的接口方法 
           {
               Console.WriteLine("Cat Description!");
           }
           new public void Shout()//重新实现接口方法 
           {
               Console.WriteLine("Cat Shout.");
           }
       }

    clip_image008

    3. 显式接口实现

    实现接口有隐式实现和显式实现两种方式。当多个接口中包含名称和签名都相同的方法时,要使用显示接口方法实现。

       public interface IDemo1
       {
           void Func();
       }
       public interface IDemo2
       {
           void Func();
       }
       public class Demo : IDemo1, IDemo2
       {
           public void Func()
           {
               Console.WriteLine("Demo.Func()");
           }
           void IDemo1.Func()
           {
               Console.WriteLine("IDemo1.Func()");
           }
           void IDemo2.Func()
           {
               Console.WriteLine("IDemo2.Func()");
           }
       }

    class Program
       {
           static void Main(string[] args)
           {
               Demo demo = new Demo();
               demo.Func();//调用Demo类中的公共方法Func()
               ((IDemo1)demo).Func(); //显式调用IDemo1中的Func()
               ((IDemo2)demo).Func(); //显式调用IDemo2中的Func()
               Console.Read();
           }
       }

    调用结果:

    clip_image010

    显式接口实现要注意:

    • 不允许指定访问性,如Public等;查看元数据时会发现它自动标记为Private。
    • 不能标记为virtual。
    • 显式接口应该慎重使用,因为值类型的实例在转型为接口时会发生装箱,而且显式接口方法不能被派生类继承。

    4.泛型接口

    FCL提供了很多现成的接口如IComparable,同时提供了其泛型接口形式IComparable<T>.这样做能够编译时就检测类型从而提高了类型安全,而且减少了参数向object类型转换的装箱拆箱操作,提高了性能。

    int x = 1;

    IComparable y = "2";

    y.CompareTo(x); //编译通过,运行时错误
    IComparable<int> z = 3;
    z.CompareTo(x); //编译通过,运行通过

    5. 基类vs接口

    • 如果存在IS-A关系使用基类,存在CAN-DO关系,使用接口。
    • 基类实现较容易一些,基类提供的功能派生类一般稍作改动即可;而接口方法则要实现所有成员。
    • 版本控制:向基类添加新方法后派生类可以直接使用;向接口添加新方法后需要修改源代码并重新编译。
  • 相关阅读:
    (转)VUE + ElementUI工程
    基于现有Kubernetes集群部署KubeSphere管理平台
    找回docker容器运行命令
    .NET平台常用的框架整理
    mysql8.0修改密码
    ElementUI实现手动上传
    nginx代理出现上传文件过大解决办法
    一次 Keepalived 高可用的事故,让我重学了一遍它!
    从 1.5 开始搭建一个微服务框架——日志追踪 traceId
    强大的开源API接口可视化管理平台YApi
  • 原文地址:https://www.cnblogs.com/changrulin/p/4778645.html
Copyright © 2020-2023  润新知