C#学习之在 C# 8 中使用默认接口方法
小职 2021-01-29 来源 :https://www.infoworld.com/article/3455239/how-to-u 阅读 767 评论 0

摘要:本文主要向大家介绍了C#学习之在 C# 8 中使用默认接口方法,通过具体的内容向大家展现,希望对大家对C#的学习有所帮助。

本文主要向大家介绍了C#学习之在 C# 8 中使用默认接口方法,通过具体的内容向大家展现,希望对大家对C#的学习有所帮助。

C#学习之在 C# 8 中使用默认接口方法


C# 8 中新增了一个非常有趣的特性,叫做 默认接口方法 (又称虚拟扩展方法),这篇文章将会讨论 C# 8 中的默认接口方法以及如何使用。

 

在 C# 8 之前,接口不能包含方法定义,只能在接口中定义方法签名,还有一个就是接口的成员默认是 public 和 abstract , 在 C# 8 之前,接口不能包含字段,也不能包含private, protected, 或者 internal 的方法成员。如果你在接口中引入了一个新成员,默认情况下你必须更新实现该接口的所有子类。

 

在 C# 8 中可以在接口定义方法的默认实现,而且还可以定义接口成员为 private,protect,甚至是 static,还有一点挺奇葩的,一个接口的 protect 成员是不能被实现类所访问的,相反,它只能在子接口中被访问,接口的 virtual 成员可以由派生接口 override,但不能被派生类 override,还有一点请注意,接口目前还不能定义 实例成员。

 

为什么要使用默认接口方法

 

所谓的 默认接口方法 指的是接口中定义了一个默认实现的方法, 如果实现该接口的类没有实现默认接口方法的话,那么这个 默认接口方法 只能从接口上进行访问,这是一个很有用的特性,因为它可以帮助开发人员在不破坏现有功能的情况下向接口的未来版本添加新方法。

 

考虑下面的 ILogger 定义。

 

public interface ILogger

   {

       public void Log(string message);

   }

下面的两个类扩展了ILogger接口并实现了Log()方法。

 

public class FileLogger : ILogger

  {

      public void Log(string message)

      {

          //Some code

      }

  }

 

  public class DbLogger : ILogger

  {

      public void Log(string message)

      {

          //Some code

      }

  }

现在假设你想在ILogger接口中新增一个方法,该方法接受两个参数:一个 文本 一个 日志级别,下面的代码片段展示了日志级别的枚举类。

 

public enum LogLevel

  {

      Info, Debug, Warning, Error

  }

修改后的 ILogger 接口如下:

 

public interface ILogger

   {

       public void Log(string message);

       public void Log(string message, LogLevel logLevel);

   }

好了,现在问题来了,因为 ILogger 中新增了一个 Log 方法,你必须要在所有实现该接口的所有子类中实现 Log(string message, LogLevel logLevel) 方法,这就很尴尬了,如果不这样做的话,编译器肯定是不会放行的,在现实情况下,这个接口实现类可能在多个 dll 中,甚至在多个团队中,可想而知,这个工作量是非常大并且非常痛苦的。

 

默认接口方法案例

 

这就是 默认接口方法 的应用场景,你可以在接口中定义一个默认方法是实现,如下代码所示:

 

public interface ILogger

  {

      public void Log(string message);

 

      public void Log(string message, LogLevel logLevel)

      {

          Console.WriteLine("Log method of ILogger called.");

          Console.WriteLine("Log Level: "+ logLevel.ToString());

          Console.WriteLine(message);

      }

  }

这个时候,实现 ILogger 接口的子类可以不实现新的 Log(string message, LogLevel logLevel) 方法,因此下面的代码也是跑的通的,编译器不会抛出任何错误。

 

public class FileLogger : ILogger

   {

       public void Log(string message)

       {

           //Some code

       }

   }

 

   public class DbLogger : ILogger

   {

       public void Log(string message)

       {

           //Some code

       }

   }

默认接口方法不能被继承

 

现在创建一个 FileLogger 类实例,然后直接调用新的带参数的 Log() 方法,如下代码所示:

 

FileLogger fileLogger = new FileLogger();

fileLogger.Log("This is a test message.", LogLevel.Debug);

 

 C#学习之在 C# 8 中使用默认接口方法

从上面图可看出 默认接口方法 不能被子类继承,换句话说,子类根本就不知道接口中还有带参数的 Log() 方法。

 

默认接口方法和菱形问题

 

现在有一个非常重要的问题,默认接口方法如何避免 菱形问题?换句话说就是 接口的 多继承 问题,考虑下面的代码清单。

 

public interface A

    {

        public void Display();

    }

 

    public interface B : A

    {

        public void Display()

        {

            Console.WriteLine("Interface B.");

        }

    }

 

    public interface C : A

    {

        public void Display()

        {

            Console.WriteLine("Interface C.");

        }

    }

 

    public class MyClass : B, C

    {

 

    }

当编译上面代码时,会抛出一个编译错误,说 MyClass 没有实现 A.Display() 方法,解决这个问题很简单,在 MyClass 中实现一下接口方法就可以了,如下代码所示:

 

public interface A

    {

        public void Display();

    }

    public interface B : A

    {

        public void Display()

        {

            Console.WriteLine("Interface B.");

        }

    }

    public interface C : A

    {

        public void Display()

        {

            Console.WriteLine("Interface C.");

        }

    }

    public class MyClass : B, C

    {

        public void Display()

        {

            Console.WriteLine("MyClass.");

        }

    }

接下来就可以生成 MyClass 实例了,然后再调用 Display() 方法,如下代码所示:

 

static void Main(string[] args)

        {

            A obj = new MyClass();

            obj.Display();

            Console.Read();

        }

现在问题来了,到底是哪一个 Display() 方法被调用了呢?为了避免歧义,C# 将会使用最近覆盖规则,即 Class.Display() 方法被最先调用。

 

抽象类 VS 接口

 

到这里,我想你肯定有疑问,抽象类 和 接口 是不是很相似了,甚至可以互换了?虽然抽象类和接口现在看起来在很多方面都很相似,但两者之间还是有微妙的区别的,具体如下:

 

抽象类可以有实例成员,接口则不能。

抽象类不能多继承,接口还是可以的。

默认接口方法 允许开发人员利用 trait 编程技术,该技术可以让那些附属于该方法的不相关类型得以继续使用,可能你有点懵,我举个例子:假设你构建好了一个dll,被很多的开发人员所使用,现在你要发布该 dll 的新版本,比如说往接口中添加了新方法,这个时候你可以定义默认实现,这样就可以对已使用的开发者进行无感升级。



关注“职坐标在线”(Zhizuobiao_Online)公众号,免费获取学习教程资料、技术就业咨询

C#学习之在 C# 8 中使用默认接口方法

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程