博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#8接口
阅读量:3527 次
发布时间:2019-05-20

本文共 4426 字,大约阅读时间需要 14 分钟。

目录


介绍

众所周知,C8.0几天前就已发布。这个版本的C#提供了许多令人兴奋的功能。接口也发生了大量的变化,因此在本文中,我们将尝试探索新功能,并尝试了解如何在项目中使用它们。

接口的今天

作为开发人员,我们都使用接口,无论是创建松散耦合的组件还是定义应由具体类实现的契约。今天的接口永远不会出现方法身体,没有修饰符。实现者类负责提供方法体并为其分配一些修饰符。如果类没有实现该方法,编译器会捕获它并提供错误,说我们需要实现该接口。

在整个应用程序中,我们将使用Logger类的示例并相应地进行更改。

using System;public interface ILogger{void Log(string Info);}public class TextLogger : ILogger{ public void Log(string Info)=> Console.Write("In base Logger");}

我们定义了一个拥有一个Log()方法的ILogger接口。我们有一个叫做实现接口ILoggerTextLogger类。考虑到当前的设计状态,这是完全正常的。现在,当我们想要扩展ILogger并且需要在其中添加更多信息时,会出现问题,如下所示:

public interface ILogger{void Log(string info);void Log(string typeofInformation,string info)}

现在我们将遇到一个问题,因为这个新方法必须由使用此接口的类实现,编译器将向我们显示错误,直到完成如下所示:

现在考虑到这个接口被多个类使用,这将打破许多变化,并且根据使用此接口的位置在实现中进行这些更改将非常痛苦。我们需要实现这个方法,以便我们的代码编译。为了克服这个问题,C8想出了接口中的默认方法。

默认接口方法

C8.0中获得此功能的主要原因是为接口方法提供默认实现,那么我们该如何做呢?我们来看下面的例子:

using System; public interface ILogger{ void Log(string info); //Default implementation void LogInfo(string typeofInformation,//string info)=>Console.Write(typeofInformation+ " " + info); }public class TextLogger : ILogger { public void Log(string info)=> Console.Write("In base Logger"); }

在这里,我们可以在接口本身看到,我们已经为该函数提供了实现。这里,我们的类TextLogger不需要实现这个方法,也不会有任何编译时错误。现在,为了在我们的应用程序中使用此接口,让我们改变我们的main方法,让我们看看我们如何使用它。

class Program    {        static void Main(string[] args)        {           ILogger _logger = new TextLogger();           _logger.LogInfo("Test","test"); // It will call the Default method of the interface        }        }}

我们需要检查的另一件事是,只有在将类作为接口进行上下文处理时,默认方法才有效。如果我们不这样做,那么默认方法实现将无法使用:

在上面的截图中,我们可以看到从类创建对象时,我们可以看到默认方法无法使用。如果我们仔细研究这个特性,我们可以看到这可能导致众所周知的多重继承问题,这个问题被称为钻石问题。根据设计,C#不会遇到任何问题,因为类和接口没有多重继承,没有方法的实现,但是使用默认方法,这将会改变。让我们看看如何在C8.0中处理它。

钻石问题

钻石问题是语言中的一个大问题,因为C#类不支持这种多重继承的结果,但是接口可以在某种程度上引入这个问题。让我们看看C#如何处理它们。下图说明了钻石问题:

上图很好地描述了钻石问题。现在,让我们看看默认接口如何产生这个问题以及C#如何处理它。让我们设计如下接口:

Interface First{    void WritetoConsole() => Console.Write("In First");}interface Second:First{ void First.WritetoConsole()=>Console.Write("In Second");}interface Third:First{  void First.WritetoConsole()=>Console.Write("In Third");}class FinalClass : Second,Third{}

在编写此代码时,我们将遇到编译时错误:

错误消息将是接口成员First.WritetoConsole()'没有最具体的实现。Second.First.WritetoConsole()“ Third.First.WritetoConsole()都不是最特殊的。(CS8705DefaultInterfaceDemo]。为了解决错误本身所描述的这个问题,我们需要在执行时提供最具体的覆盖,Dotnet设计团队已经具体告诉它,如下,接口成员的类实现应该总是赢得接口中的默认实现,即使它是从基类继承的。默认实现总是只在类没有任何成员实现时才会回滚。让我们看看我们如何提供默认实现并解决这个钻石问题。

using System;interface First{    void WritetoConsole() => Console.Write("In First");}interface Second:First{ void First.WritetoConsole()=>Console.Write("In Second");}interface Third:First{  void First.WritetoConsole()=>Console.Write("In Third");}class FinalClass : Second,Third{  void First.WritetoConsole(){  Console.Write("From Final class");}}

接口中的修饰符

传统上,直到C8.0的到来,我们无法在接口中使用修饰符。在C8.0中,我们可以使用它们,至今修饰符像privateprotectedinternalpublicvirtual是允许的。在设计上,所有默认接口的方法都是virtual,除非我们将它们设置为privatesealed。没有正文的所有成员在默认情况下都被视为抽象,因此必须在具体类中实现。

using System;interface IInterfaceModifiers{  //By Default default method is private  virtual void DefaultMethod()=>Console.WriteLine("Default method");  //Private Default Method  private void privatedefaultmethod()=>Console.WriteLine(" private Default method");  //Protected Default Method  protected void ProtectedDefaultMethod()=>Console.WriteLine(" protected Default method");  // Public Default Method  public void PublicDefaultMethod()=>Console.WriteLine(" public Default method");  virtual void VirtualDefaultMethod()=>Console.WriteLine("Virtual Default method");  abstract void AbstractDefaultMethod();}

class InterfaceModifierDemo : IInterfaceModifiers{ public void AbstractDefaultMethod() => Console.WriteLine("Abstract virtual method");}namespace DeaultInterfaceDemo{ class Program { static void Main(string[] args) { IInterfaceModifiers i= new InterfaceModifierDemo(); i.AbstractDefaultMethod(); i.DefaultMethod(); i.PublicDefaultMethod(); i.VirtualDefaultMethod(); } }}

当我们运行上面的代码时,我们可以在控制台上看到以下输出:

Abstract virtual methodDefault methodpublic Default methodVirtual Default method

除此之外,我在这个例子中遇到的观察很少。当我们使一个方法成为virtual时,我们可以在接口本身中重写该方法,并且我们不能在实现类中重写它。当我们创建一个protected方法时,它在继承接口中可用,而不是实现类。默认情况下,接口的成员是abstract,这使得实现类必须正确实现它们。

总结

我们已经看到了C8.0中最具争议但最激动人心的特性。它将改变我们在设计中使用接口的方式,这肯定会帮助开发人员产生更少的重大变化,但它也会提出自己的性能和设计视角的挑战。要添加的另一件事是,此功能目前在.NET框架中不可用,但包含在.NET CoreCore CLR以及MONO中。

参考

 

原文地址:

转载地址:http://bvzhj.baihongyu.com/

你可能感兴趣的文章
[LeetCode javaScript] 735. 行星碰撞
查看>>
[LeetCode javaScript] 125. 验证回文串
查看>>
[LeetCode javaScript] 226. 翻转二叉树
查看>>
[LeetCode javaScript] 520. 检测大写字母
查看>>
[LeetCode javaScript] 350. 两个数组的交集 II
查看>>
[LeetCode javaScript] 53.最大子序和
查看>>
[LeetCode javaScript] 101. 对称二叉树
查看>>
[LeetCode javaScript] 860. 柠檬水找零
查看>>
[LeetCode javaScript] 118. 杨辉三角
查看>>
[LeetCode javaScript] 905. 按奇偶校验排序数组
查看>>
[LeetCode javaScript] 617. 合并二叉树
查看>>
[LeetCode javaScript] 292. Nim游戏
查看>>
[LeetCode javaScript] 896. 单调数列
查看>>
[LeetCode javaScript] 804. 唯一摩尔斯密码词
查看>>
[LeetCode javaScript] 476. 数字的补数
查看>>
[LeetCode javaScript] 811. 子域名访问计数
查看>>
[LeetCode javaScript] 414. 第三大的数
查看>>
[LeetCode javaScript] 242. 有效的字母异位词
查看>>
[LeetCode javaScript] 75. 颜色分类
查看>>
[LeetCode javaScript] 179. 最大数
查看>>