三联网站建设,山东莱芜金点子电子版,大型网站技术架构:核心原理与案例分析,小企业网站建设公司C# 8 中新增了一个非常有趣的特性#xff0c;叫做 默认接口方法 (又称虚拟扩展方法)#xff0c;这篇文章将会讨论 C# 8 中的默认接口方法以及如何使用。在 C# 8 之前#xff0c;接口不能包含方法定义#xff0c;只能在接口中定义方法签名#xff0c;还有一个就是接口的成员… C# 8 中新增了一个非常有趣的特性叫做 默认接口方法 (又称虚拟扩展方法)这篇文章将会讨论 C# 8 中的默认接口方法以及如何使用。在 C# 8 之前接口不能包含方法定义只能在接口中定义方法签名还有一个就是接口的成员默认是 public 和 abstract , 在 C# 8 之前接口不能包含字段也不能包含private, protected, 或者 internal 的方法成员。如果你在接口中引入了一个新成员默认情况下你必须更新实现该接口的所有子类。在 C# 8 中可以在接口定义方法的默认实现而且还可以定义接口成员为 privateprotect甚至是 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);从上面图可看出 默认接口方法 不能被子类继承换句话说子类根本就不知道接口中还有带参数的 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 的新版本比如说往接口中添加了新方法这个时候你可以定义默认实现这样就可以对已使用的开发者进行无感升级。译文链接https://www.infoworld.com/article/3455239/how-to-use-default-interface-methods-in-csharp-8.html