【5min+】 巨大的争议?C# 8 中的接口

介绍

【五分钟的dotnet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net知识等等。
5min+不是超过5分钟的意思,"+"是知识的增加。so,它是让您花费5分钟以下的时间来提升您的知识储备量。

正文

伴随着 .NET Core 3.0 一起发布的 C# 8 ,从发布至今已经过了快大半年了。如果您细心的话,就能发现在C# 8新增的功能中有一条:“默认接口方法” 。半年前当我看到这一新特性的时候,我惊呆了,但是惊讶之余是更多的疑惑。因为对于接口这个东西来说,从C#发布至今的十多年里几乎一直保持它的样子,然而在C# 8之后,它有了巨大的变化。随着而来,也是各种争论的声音。

很早之前我就想写这篇文章了,但是由于各种原因一直拖延到了现在。

先让我们来回顾一下 C# 中原有的接口有什么特点:

  • 接口类似于只有抽象成员的抽象基类。实现接口的任何类或结构都必须实现其所有成员。

  • 接口无法直接进行实例化。其成员由实现接口的任何类或结构来实现。

  • 接口可以包含事件、索引器、方法和属性。

  • 接口不含方法的实现。

  • 一个类或结构可以实现多个接口。一个类可以继承一个基类,还可实现一个或多个接口。

也正是基于这些特点,当我们在接口中为一个方法加上"pulic"等关键字的时候,编译器会提示我们这是一个错误的写法:

复制代码

interface IRepository
{//Compile-time error CS0106 The modifier 'public' is not valid for this item.public void Add();
}

所以更不用谈给方法写一个实现了。这就让它和 C# 中的另外一种事物行成了鲜明的对比,是的,抽象类。不知道大家有没有在各种面试中遇到过这样的提问:“接口能有任何的访问修饰符吗?”,“接口和抽象类的区别是什么?”

曾经您可以和自然的脱口而出答案:“没有修饰符。一个可以有默认方法,一个只能申明方法…………”。但是从现在开始:这些答案是错的了。????

这是微软MSDN中的设计规范截图:

上面的图是我半年前截的图,今天本来想去找对应的链接分享出来,但是发现找不到了。可能…………

新的接口

好了,说了那么多,我们来看看C# 8 为我们改变后的接口是什么样子:

复制代码

enum LogLevel
{Information,Warning,Error
}interface ILogger
{void WriteCore(LogLevel level, string message);void WriteInformation(string message){WriteCore(LogLevel.Information, message);}void WriteWarning(string message){WriteCore(LogLevel.Warning, message);}void WriteError(string message){WriteCore(LogLevel.Error, message);}
}class ConsoleLogger : ILogger
{public void WriteCore(LogLevel level, string message){Console.WriteLine($"{level}: {message}");}
}class TraceLogger : ILogger
{public void WriteCore(LogLevel level, string message){switch (level){case LogLevel.Information:Trace.TraceInformation(message);break;case LogLevel.Warning:Trace.TraceWarning(message);break;case LogLevel.Error:Trace.TraceError(message);break;}}
}ILogger consoleLogger = new ConsoleLogger();
consoleLogger.WriteWarning("Cool no code duplication!");  // Output: Warning: Cool no Code duplication!ILogger traceLogger = new TraceLogger();
consoleLogger.WriteInformation("Cool no code duplication!");  // Cool no Code duplication!

这是我在网上摘取的一部分代码。是的,您没有看错,接口可以实现方法了。并且还可以给它添加上访问修饰符:

复制代码

interface IDemoInterface
{public static int staticIntValue = 123;   //Rightpublic void PulicMethod(){ }  //Right
}

就像您所见的一样,它还可以在内部声明静态的数据。

但是下面的写法依旧会提示错误哦:

复制代码

interface IDemoInterface
{abstract void M1() { } //Error. 因为有abstractabstract private void M2() { } //Errorabstract static void M3() { } //Errorstatic extern void M4() { } //Error.因为有extern
}

争议点

走到这里,也许您会说:“这不挺好的吗?好像对我也没有啥影响。” 确实,假如您不更改接口的签名,无论您是否在接口中增加默认实现还是某些静态数据都不会对已有的应用程序造成任何错误。

但是如果您经常使用抽象类的话,您就会发现,这样的接口是不是和抽象类太像了?甚至有点完全掩盖了抽象类的优势。

当我半年前看到这一新特性时,我就产生了这样的疑惑。这个 “默认方法实现” 的新特性,真的需要吗?如果需要,那我如何选择它和抽象类?

结果我发现,大家都对这一特性产生了困惑:

于时,我抱着怀疑的态度在网上到处搜索答案。最后在C# 官方团队的笔记中我看到了这样一句话:

这句话的意思大致是:我们应该更深入地研究Java在这里所做的事情,Java对接口的实现很好,我们应该…………(有关该说明的github链接可以点击这里)。

我当时心就凉了半截。不过缓了缓,我镇定的思考了一下:好的语言设计被借鉴和参考也是很有必要的。比如现在其它语言都在借鉴C#的await和async。(PS:C#和Typescript怎么越来越像????)。

那么我们真的需要在接口中提供默认实现吗?那什么情况下我需要这样做?毕竟咱们使用了 C# 这么多年,就算接口没有提供默认实现也能设计出很好的系统来。所以为了解决上面的疑问,还是得回到接口和抽象类的本质。

按照咱们以往使用接口和抽象类的情况来看:接口表示的是一种行为,"who can"(比如鸟会飞),而基类表示的是一种类别,"is a"(比如麻雀是鸟)。因此在OOP的世界中,如果咱们细心的来建模的话,我们会把表示行为的共性抽象为一个接口:比如鸟会飞,咱们可以抽象一个IFly的接口。对老版本的 C# 来说,不能提供方法的实现,所以只会有一个Fly() 的方法签名。而现在我们通过新的特性,我们可以给“飞”这个动作提供一个默认的实现,比如 90%的鸟都是“煽动翅膀起飞”,则我们可以将这个大部分 的操作作为默认实现,而对那些10%的 “小众” 进行重写。也正是由于接口更关注的是“行为”,所以接口中不能存在“状态”,因此您会发现虽然可以声明字段了,但是只能声明静态字段。而实例化的状态信息依旧只能通过抽象类来实现。

当然,在现在接口和抽象类建模比较模糊的今天,从技术的实现上来说,其实接口的默认实现并没有带来很多技术编码上的好处。但是如果您坚持好的规范抽象,比如接口开头就是用“I”,将对象的行为进行抽象提升为接口,也许某一刻您会感受到该特性带来的改变。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[蓝桥杯2016初赛]寒假作业-next_permutation枚举

暴搜代码&#xff08;耗时较长&#xff0c;要90s左右&#xff09;如下&#xff1a; #include <iostream> using namespace std; const int N 15; int a[N]; bool st[N]; int cnt;void dfs(int u) {if (u 13) {if (a[1] a[2] a[3] && a[4] - a[5] a[6] &…

word List29

word List29 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

.NET Core开发实战(第5课:依赖注入:良好架构的起点)--学习笔记(上)

05 | 依赖注入&#xff1a;良好架构的起点为什么要使用依赖注入框架借助依赖注入框架&#xff0c;我们可以轻松管理类之间的依赖&#xff0c;帮助我们在构建应用时遵循设计原则&#xff0c;确保代码的可维护性和可扩展性ASP.NET Core 的整个架构中&#xff0c;依赖注入框架提供…

非常实用的word文本括号匹配是否正确的code,可按照此思路扩展到python处理大批量文本文件的检错中,非常实用!!!

非常实用的word文本括号匹配是否正确的code&#xff0c;可按照此思路扩展到python处理大批量文本文件的检错中&#xff0c;非常实用&#xff01;&#xff01;&#xff01; 原理&#xff1a; 栈 代码&#xff1a; #include <stdio.h> #include <stdlib.h> #includ…

分区式存储管理c++_分区机要变形缝,纵横交接卫浴厨:防火阀参数的高效记忆口诀...

防火阀也是常考点&#xff0c;特别是设置部位、温度&#xff0c;是最容易考的地方。记起来有点麻烦&#xff0c;从中提取精炼一下&#xff0c;可以用如下6句话&#xff0c;就能记住。防火阀与排烟防火阀重点参数记忆要领&#xff1a;分区机要变形缝&#xff0c;纵横交接卫浴厨独…

ASP.NetCore+VUE 源码获取成绩管理系统(二)

雨水来了明天是二十四节气中的雨水&#xff0c;希望能给干燥的春天带来新的生机&#xff0c;抖擞抖擞精神迎接新的一天吧。上篇文章ASP.NetCoreVUE 实现学生成绩管理系统(一) 中&#xff0c;我对我开发的项目做了简单的说明&#xff0c;发现还是有很多小伙伴感兴趣的&#xff0…

word List 30

word List 30 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

研发协同平台持续交付之代理服务实践

源宝导读&#xff1a;插件系统大大提高了系统的扩展性&#xff0c;有利于模块化开发。系统发布后&#xff0c;当我们需要对系统进行扩充&#xff0c;可以再不编译的情况下更新系统的插件即可。基于热拔插的软件系统提高了持续交付能力&#xff0c;在添加新特性的同时保持核心结…

vscode python 自动补全_利用CodeBERT,这个VS Code扩展可以自动生成Python文档字符串...

机器之心报道编辑&#xff1a;魔王该扩展利用可处理编程语言和自然语言的预训练模型 CodeBERT&#xff0c;实现快速生成 Python 文档字符串的功能。Visual Studio Code(简称 VS Code)是一个由微软开发&#xff0c;同时支持 Windows、 Linux 和 macOS 等操作系统的免费代码编辑器…

[蓝桥杯2016初赛]报纸页数-生活常识+思维

题目描述 X星球日报和我们地球的城市早报是一样的&#xff0c;都是一些单独的纸张叠在一起而已。每张纸印有4版。 比如&#xff0c;某张报纸包含的4页是&#xff1a;5,6,11,12&#xff0c;可以确定它应该是最上边的第2张报纸。 我们在太空中捡到了一张X星球的报纸&#xff0c;…

great English sentence:

great English sentence: Therefore,everyone needs to find their extra ——their unique value contribution that make them stand out in whatever is their field of emploment. 因此&#xff0c;每个人必须去找到独特点&#xff0c;这个独特点就是他们唯一的价值创造的…

2020 年 5 大 DevOps 趋势

由于高效率和较快的部署能力&#xff0c;DevOps 正在一步步地塑造着软件世界&#xff0c;并进入主流领域。而随着 DevOps 逐步成熟&#xff0c;它也将继续改变全球的 IT 和数字管理。为了促进各方更加了解 DevOps&#xff0c;并为即将到来的一切做好准备&#xff0c;一位名为 G…

datagridview实时更新数据_旭诺云盒|智能办公新趋势进出口数据自动提取,通关状态实时更新...

春节期间&#xff0c;很多公司同事都被滞留在老家无法返回公司上班&#xff0c;为了保证公司业务正常运转&#xff0c;同事之间依靠邮件、微信、QQ等工具进行文件和数据的传递&#xff0c;增加了很多数据整理时间。且电子口岸、单一窗口这些进出口企业频繁使用的平台&#xff0…

排名前15位的Kubernetes监控和安全工具

Kubernetes推动了竞争力的提升。如今&#xff0c;作为一项成熟的技术&#xff0c;全球各地的企业都在迅速采用基于微服务的&#xff0c;容器驱动的方法来交付软件。Kubernetes是行业标准。行业领导者正在帮助它如雨后春笋般发展&#xff0c;基于Kubernetes核心开发综合应用程序…

word List 31

word List 31 如果存在什么问题&#xff0c;欢迎批评指正&#xff01;谢谢&#xff01;

什么是python语言的动态类型机制_理解Python的Dynamic typing

Python的Dynamic typing有些类似于C语言的指针&#xff0c;在C中&#xff0c;一个变量可以指向任何地址空间&#xff0c;在Python中&#xff0c;一个变量也可以指向任何type的数据对象。变量的指向可以在程序运行过程中变化&#xff0c;这就是我理解的Dynamic typing。 Python是…

Asp.Net Core IdentityServer4 管理面板集成

前言IdentityServer4&#xff08;以下简称 Id4&#xff09; 是 Asp.Net Core 中一个非常流行的 OpenId Connect 和 OAuth 2.0 框架&#xff0c;可以轻松集成到 Asp.Net Core 应用中&#xff0c;并且与 Asp.Net Core Identity 也可以轻松集成。博客园也有大佬发布了很多关于 Id4…

数据结构---递归实现十进制装换为任意进制

数据结构—递归实现十进制装换为任意进制 代码&#xff1a; #include <stdio.h> #include <stdlib.h> #include"stack.h" stack Stack; void toAnyDigit(int n, int d) {//十进制转化为d进制if (n 0) {//递归结束的条件return;}int temp n % d;push(…

c++ string 删除字符_字符串操作的全面总结(附完整代码)

字符串操作看似简单&#xff0c;其实非常重要&#xff0c;不注意的话&#xff0c;经常出现代码运行结果和自己想要的不一致&#xff0c;甚至崩溃。本文总结了一些构建string对象方法、修改string对象的方法、string类型的操作函数、string类型的查找、string对象的比较。1 构建…

给Hangfire的webjob增加callback和动态判断返回结果功能设计

背景介绍通常业务中需要用到定时执行功能&#xff0c;我用hangfire搭建了一个调度服务&#xff0c;这个调度服务是独立于业务逻辑的&#xff0c;具体可以参考文章&#xff1a;https://github.com/yuzd/Hangfire.HttpJob/wiki也就是说只要我有了这个调度服务后&#xff0c;只要提…