共计 2977 个字符,预计需要花费 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);
从下面图可看出 默认接口办法
不能被子类继承,换句话说,子类基本就不晓得接口中还有带参数的 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/art…