C#8.0 中使用默认接口成员更新接口
从 .NET Core 3.0 上的 C# 8.0 开始,可以在声明接口成员时定义实现。 最常见的方案是安全地将成员添加到已经由无数客户端发布并使用的接口。
在本教程中,你将了解:
- 通过使用实现添加方法,安全地扩展接口。
- 创建参数化实现以提供更大的灵活性。
- 使实现器能够以替代的形式提供更具体的实现。
需要将计算机设置为运行 .NET Core,包括 C# 8.0 预览版编译器。 从 Visual Studio 2019 或最新的 .NET Core 3.0 预览版 SDK 开始,可以使用 C# 8.0 预览版编译器。 从 .NET Core 3.0 预览版 4 开始提供默认接口成员。
public interface ICustomer
{
IEnumerable<IOrder> PreviousOrders { get; } DateTime DateJoined { get; }
DateTime? LastOrder { get; }
string Name { get; }
IDictionary<DateTime, string> Reminders { get; }
}
他们定义了表示订单的第二个接口:
public interface IOrder
{
DateTime Purchased { get; }
decimal Cost { get; }
}
通过这些接口,团队可以为其用户生成一个库,以便为其客户创造更好的体验。 他们的目标是与现有客户建立更深入的关系,并改善他们与新客户的关系。
现在,是时候为下一版本升级库了。 其中一个请求的功能可以为拥有大量订单的客户提供忠实客户折扣。 无论客户何时下单,都会应用这一新的忠实客户折扣。 该特定折扣是每位客户的财产。 ICustomer 的每个实现都可以为忠实客户折扣设置不同的规则。
添加此功能的最自然方式是使用用于应用任何忠实客户折扣的方法来增强 ICustomer 接口。 此设计建议引起了经验丰富的开发人员的关注:“一旦发布,接口就是固定不变的! 这是一项突破性的变革!” C# 8.0 添加了默认接口实现 用于升级接口。 库作者可以向接口添加新成员,并为这些成员提供默认实现。
默认接口实现使开发人员能够升级接口,同时仍允许任何实现器替代该实现。 库的用户可以接受默认实现作为非中断性变更。 如果他们的业务规则不同,则可以进行替代。
团队就最有可能的默认实现达成一致:针对客户的忠实客户折扣。
升级应提供用于设置两个属性的功能:符合折扣条件所需的订单数量以及折扣百分比。 这使其成为用于默认接口成员的完美方案。 可以向 ICustomer 接口添加方法,并提供最有可能的实现。 所有现有的和任何新的实现都可以使用默认实现,或者提供其自己的实现。
首先,将新方法添加到实现中:
// Version 1:
public decimal ComputeLoyaltyDiscount()
{
DateTime TwoYearsAgo = DateTime.Now.AddYears(-);
if ((DateJoined < TwoYearsAgo) && (PreviousOrders.Count() > ))
{
return 0.10m;
}
return ;
}
库作者编写了用于检查实现的第一个测试:
SampleCustomer c = new SampleCustomer("customer one", new DateTime(, , ))
{
Reminders =
{
{ new DateTime(, , ), "childs's birthday" },
{ new DateTime(, , ), "anniversary" }
}
};
SampleOrder o = new SampleOrder(new DateTime(, , ), 5m);
c.AddOrder(o);
o = new SampleOrder(new DateTime(, , ), 25m);
c.AddOrder(o);
// 检查折扣
ICustomer theCustomer = c;
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");
注意测试的以下部分:
// 检查折扣
ICustomer theCustomer = c;
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");
从 SampleCustomer 到 ICustomer 的强制转换是必需的。 SampleCustomer 类不需要为 ComputeLoyaltyDiscount 提供实现;这由 ICustomer 接口提供。 但是,SampleCustomer 类不会从其接口继承成员。 该规则没有更改。 若要调用在接口中声明和实现的任何方法,该变量的类型必须是接口的类型,在本示例中为 ICustomer。
// Version 2:
public static void SetLoyaltyThresholds(TimeSpan ago, int minimumOrders = , decimal percentageDiscount = 0.10m)
{
length = ago;
orderCount = minimumOrders;
discountPercent = percentageDiscount;
}
private static TimeSpan length = new TimeSpan( * , ,,); // 2年
private static int orderCount = ;
private static decimal discountPercent = 0.10m; public decimal ComputeLoyaltyDiscount()
{
DateTime start = DateTime.Now - length; if ((DateJoined < start) && (PreviousOrders.Count() > orderCount))
{
return discountPercent;
}
return ;
}
这个小代码片段中展示了许多新的语言功能。 接口现在可以包含静态成员,其中包括字段和方法。 还启用了不同的访问修饰符。 其他字段是专用的,新方法是公共的。 接口成员允许使用任何修饰符。
使用常规公式计算忠实客户折扣但参数有所不同的应用程序不需要提供自定义实现;它们可以通过静态方法设置自变量。 例如,以下代码设置“客户答谢”,奖励任何成为会员超过一个月的客户:
ICustomer.SetLoyaltyThresholds(new TimeSpan(, , , ), , 0.25m);
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");
目前添加的代码提供了方便的实现,可用于用户需要类似默认实现的项目的方案,或用于提供一组不相关的规则。 对于最后一个功能,让我们稍微重构一下代码,以实现用户可能需要基于默认实现进行生成的方案。
假设有一家想要吸引新客户的初创企业。 他们为新客户的第一笔订单提供 50% 的折扣, 而现有客户则会获得标准折扣。 库作者需要将默认实现移入 protected static 方法,以便实现此接口的任何类都可以在其实现中重用代码。 接口成员的默认实现也调用此共享方法:
public decimal ComputeLoyaltyDiscount() => DefaultLoyaltyDiscount(this);
protected static decimal DefaultLoyaltyDiscount(ICustomer c)
{
DateTime start = DateTime.Now - length; if ((c.DateJoined < start) && (c.PreviousOrders.Count() > orderCount))
{
return discountPercent;
}
return ;
}
在实现此接口的类的实现中,替代可以调用静态帮助程序方法,并扩展该逻辑以提供“新客户”折扣:
public decimal ComputeLoyaltyDiscount()
{
if (PreviousOrders.Any() == false)
return 0.50m;
else
return ICustomer.DefaultLoyaltyDiscount(this);
}
可以在我们位于 [GitHub 上的示例存储库]中查看整个完成的代码(可以在 GitHub 上的示例存储库中获取入门应用程序)。
这些新功能意味着,当这些新成员拥有合理的默认实现时,接口可以安全地更新。 精心设计接口,以表达可由多个类实现的单个功能概念。 这样一来,在发现针对同一功能概念的新要求时,可以更轻松地升级这些接口定义。
C#8.0 中使用默认接口成员更新接口的更多相关文章
- C# 8.0 中开启默认接口实现
原文:C# 8.0 中开启默认接口实现 当你升级到 C# 8.0 和 .NET Core 3.0 之后,你就可以开始使用默认接口实现的功能了. 从现在开始,你可以在接口里面添加一些默认实现的成员,避免 ...
- 在Tomcat7.0中设置默认服务器和不加端口名访问
前言 昨天买了域名,服务器,然后搭建了环境,然后想他通过默认的端口,不用端口就访问. 设置WEB项目的欢迎页 在WEB-INF文件夹下有个web.xml文件(最近新建的项目不包含此文件,可以手动新建) ...
- Springboot2.0中jpa默认创建的mysql表为myisam引擎问题
使用Springboot2.0后,使用jpa操作mysql数据库时,默认创建的表的引擎是myisam,myisam是不能加外键的,找了一些资源,最终可以用此方法解决! yml格式: spring: j ...
- Vue.js2.0中的变化(持续更新中)
最近自己在学习Vue.js,在看一些课程的时候可能Vue更新太块了导致课程所讲知识和现在Vue的版本不符,从而报错,我会在以后的帖子持续更新Vue的变化与更新,大家也可以一起交流,共同监督学习! 1. ...
- IHostingEnvironment VS IHostEnvironment - .NET Core 3.0中的废弃类型
原文: https://andrewlock.net/ihostingenvironment-vs-ihost-environment-obsolete-types-in-net-core-3/ 作者 ...
- asp.net core 3.0 中使用 swagger
asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...
- [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现
9月份的时候,微软宣布正式发布C#8.0,作为.NET Core 3.0发行版的一部分.C#8.0的新特性之一就是默认接口实现.在本文中,我们将一起来聊聊默认接口实现. 众所周知,对现有应用程序的接口 ...
- JDK8.0接口中的默认方法和静态方法
我们在接口中通常定义的方法是抽象方法,即没有方法体,只有返回值类型和方法名:(public abstract) void Method(); 类在实现接口的时候必须重写抽象方法才可以 jdk8中新加的 ...
- Java接口成员变量和方法默认修饰符
Java的interface中,成员变量的默认修饰符为:public static final 所以我们在interface中定义成员变量的时候,可以 1:public static final S ...
随机推荐
- 解析 Qt 字库移植并能显示中文 (上篇)
原文http://mobile.51cto.com/symbian-272552.htm 本文介绍的是Qt 字库移植并能显示中文,需要的字体库文件,一般是多个.具体移植那一个,看你使用的字库是什么了, ...
- es6基本语法,vue基本语法
一.es6基本语法 0.es6参考网站 http://es6.ruanyifeng.com/#README 1.let 和 const (1)const特点: 只在局部作用域起作用 不存在变量提升 不 ...
- Spring boot中Spring-Data-JPA操作MySQL数据库时遇到的错误(一)
执行遇到如下错误: 看错误时要注意两点: 1.控制台报错情况,一般情况下红色第一行很重要,举例:上图info之下,蓝底标出的部分. 2.这种一般是以堆栈形式描述的,也就是重点在栈底的最后的一个完整的句 ...
- System.arraycopy 和 Arrays.copyOf
System.arraycopy /* native关键字 本地方法 System类 java.lang.System.class 参数说明: src - 源数组. srcPos - 源数组中的起始位 ...
- C++标准库(体系结构与内核分析)(侯捷第一讲)
一.C++标准库介绍 C++标准库:C++ Standard Library C++标准库与STL有什么关系: STL:Standard Template Library STL包含6大部件,基本占标 ...
- http协议之状态码
=================状态码,状态文字======================== 状态码:用来反应服务器的响应状态 状态文字:是用来说明状态码的. 状态码:可以分为这5个大的部分 - ...
- 深度残差网络(ResNet)
引言 对于传统的深度学习网络应用来说,网络越深,所能学到的东西越多.当然收敛速度也就越慢,训练时间越长,然而深度到了一定程度之后就会发现越往深学习率越低的情况,甚至在一些场景下,网络层数越深反而降低了 ...
- Web自动化测试 二 ----- HTML
HTML 一.结构 html> 与 </html> 之间的文本描述网页 <body> 与 </body> 之间的文本是可见的页面内容 <h1> 与 ...
- python的数据类型之字符串(一)
字符串(str) 双引号或者单引号中的数据,就是字符串. 注意事项 1.反斜杠可以用来转义,使用r可以让反斜杠不发生转义. 2.字符串可以用+运算符连接在一起,用*运算符重复. 3.Python中的字 ...
- 机器学习读书笔记(七)支持向量机之线性SVM
一.SVM SVM的英文全称是Support Vector Machines,我们叫它支持向量机.支持向量机是我们用于分类的一种算法. 1 示例: 先用一个例子,来了解一下SVM 桌子上放了两种颜色的 ...