本文共 4426 字,大约阅读时间需要 14 分钟。
目录
众所周知,C#8.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接口。我们有一个叫做实现接口ILogger的TextLogger类。考虑到当前的设计状态,这是完全正常的。现在,当我们想要扩展ILogger并且需要在其中添加更多信息时,会出现问题,如下所示:
public interface ILogger{void Log(string info);void Log(string typeofInformation,string info)}
现在我们将遇到一个问题,因为这个新方法必须由使用此接口的类实现,编译器将向我们显示错误,直到完成如下所示:
现在考虑到这个接口被多个类使用,这将打破许多变化,并且根据使用此接口的位置在实现中进行这些更改将非常痛苦。我们需要实现这个方法,以便我们的代码编译。为了克服这个问题,C#8想出了接口中的默认方法。
在C#8.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#不会遇到任何问题,因为类和接口没有多重继承,没有方法的实现,但是使用默认方法,这将会改变。让我们看看如何在C#8.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()”都不是最特殊的。(CS8705)[ DefaultInterfaceDemo]。为了解决错误本身所描述的这个问题,我们需要在执行时提供最具体的覆盖,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");}}
传统上,直到C#8.0的到来,我们无法在接口中使用修饰符。在C#8.0中,我们可以使用它们,至今修饰符像private,protected,internal,public和virtual是允许的。在设计上,所有默认接口的方法都是virtual,除非我们将它们设置为private或sealed。没有正文的所有成员在默认情况下都被视为抽象,因此必须在具体类中实现。
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,这使得实现类必须正确实现它们。
我们已经看到了C#8.0中最具争议但最激动人心的特性。它将改变我们在设计中使用接口的方式,这肯定会帮助开发人员产生更少的重大变化,但它也会提出自己的性能和设计视角的挑战。要添加的另一件事是,此功能目前在.NET框架中不可用,但包含在.NET Core和Core CLR以及MONO中。
原文地址:
转载地址:http://bvzhj.baihongyu.com/