从未来看 C#

前言

如今 C# 虽然发展到了 8.0 版本,引入了诸多的函数式特性,但其实在 C# 未来的规划当中,还有很多足以大规模影响现有 C# 代码结构和组成的特性,本文中将会对就重要的特性进行介绍,并用代码示例展示这些特性。

以下特性将会在 C# 9.0、10.0 或者更高版本提供。

Records

Records 是一种全新的简化的 C# class 和 struct 的形式。

现在当我们需要声明一个类型用来保存数据,并且支持数据的解构的话,需要像如下一样写出大量的样板代码:

Copyclass Point : IEquatable<Point>
{public readonly double X;public readonly double Y;public Point(double X, double Y){this.X = X;this.Y = Y;}public static bool operator==(Point left, Point right) { ... }public bool Equals(Point other) { ... }public override bool Equals(object other) { ... }public override int GetHashCode() { ... }public void Deconstruct(out double x, out double y) { ... }
}

十分复杂。引入 Records 之后,上面的样板代码只需简化成一句话:

Copydata class Point(double X, double Y);

并且 Records 支持数据的变换、解构和模式匹配:

Copyvar pointA = new Point(3, 5);
var pointB = pointA with { Y = 7 };
var pointC = new Point(3, 7);// 当 Y = 5 时为 X,否则为 Y
var result = pointB switch
{(var first, 5) => first,(_, var second) => second
};// true
Console.WriteLine(pointB == pointC);

当然,record 是 immutable 的,并且是可以合并(继承)的,也可以标记为 sealed 或者 abstract

Copysealed data class Point3D(double X, double Y, double Z) : Point(X, Y);

上面的这种 record 声明方式是基于位置声明的,即 Point(first, second)fisrt 所代表的第一个位置将成为 Xsecond 所代表的第二个位置将成为 Y

还有一种声明方式是基于名称的:

Copydata class Point { double X; double Y };
var point = new Point { X = 5, Y = 6 };

Discriminated Unions

Discriminated unions 又叫做 enum class,这是一种全新的类型声明方式,顾名思义,是类型的 “枚举”。

例如,我们需要定义形状,形状有矩形、三角形和圆形,以前我们需要先编写一个 Shape 类,然后再创建 RectangleTriangle 和 Circle 类继承 Shape 类,现在只需要几行就能完成,并且支持模式匹配和解构:

Copyenum class Shape
{Retangle(double Width, double Height);Triangle(double Bottom, double Height);Circle(double Radius);Nothing;
}

然后我们就可以使用啦:

Copyvar circle = new Circle(5);
var rec = new Rectangle(3, 4);if (rec is Retangle(_, 4))
{Console.WriteLine("这不是我想要的矩形");
}var height = GetHeight(rec);double GetHeight(Shape shape)=> shape switch{Retangle(_, height) => height,Triangle(_, height) => height,_ => throw new NotSupportedException()};

利用此特性,我们可以轻而易举的实现支持模式匹配的、type sound 的可空数据结构:

Copyenum class Option<T>
{Some(T value);None;
}var x = Some(5);
// Option<never>
var y = None;void Foo(Option<T> value)
{var bar = value switch{Some(var x) => x,None => throw new NullReferenceException()};
}

Union and Interp Types

当我们想要表示一个对象是两种类型其一时,将可以使用联合类型来表达:

Copypublic type SignedNumber = short | int | long | float | double | decimal;
public type ResultModel<T> = DataModel<T> | ErrorModel;

这在 Web API 中非常有用,当我们的接口可能返回错误的时候,我们不再需要将我们的数据用以下方式包含在一个统一的模式中:

Copypublic class ResultModel<T>
{public string Message { get; set; }public int Code { get; set; }public T Data { get; set; }
}

我们将能够做到,不依赖异常等流程处理的方式做到错误时返回错误信息,请求正常处理时返回真实所需的数据:

Copypublic async ValueTask<DataModel | ErrorModel> SomeApi()
{if (...) return new DataModel(...);return new ErrorModel(...);
}

还有和类型,用来表示多个类型之和,我们此前在设计接口时,如果需要一个类型实现了多个接口,则需要定义一个新接口去实现之前的接口:

Copyinterface IA { ... }
interface IB { ... }
interface IAB : IA, IB { }void Foo(IAB obj) { ... }

有了和类型之后,样板代码 IAB 将不再需要:

Copyvoid Foo(IA & IB obj) { ... }

或者我们也可以这样声明新的类型:

Copytype IAB = IA & IB;

Bottom Type

Bottom type 是一种特殊的类型 nevernever 类型是任何类型的子类,因此不存在该类型的子类。一个 never 类型的什么都不表示。

Union types 带来一个问题,就是我们有时候需要表达这个东西什么都不是,那么 never 将是一个非常合适的选择:

Copytype Foo = Bar | Baz | never;

另外,never 还有一个重要的用途:控制代码流程,一个返回 never 的函数将结束调用者的逻辑,即这个函数不会返回:

Copyvoid | never Foo(int x)
{if (x > 5) return;return never;
}void Main()
{Foo(6);Console.WriteLine(1);Foo(4);Console.WriteLine(2);
}

上述代码将只会输出 1。

Concepts

Concepts 又叫做 type classes、traits,这个特性做到可以在不修改原有类型的基础上,为类型实现接口。

首先我们定义一个 concept

Copyconcept Monoid<T>
{// 加函数T Append(this T x, T y);// 零属性static T Zero { get; }
}

然后我们可以为这个 concept 创建类型类的实例:

Copyinstance IntMonoid : Monoid<int>
{int Append(this int x, int y) => x + y;static int Zero => 0;
}

这样我们就为 int 类型实现了 Monoid<int> 接口。

当我们想实现一个函数用来将一个 int 数组中的所有元素求和时,只需要:

Copypublic T Sum<T, inferred M>(T[] array) where M : Monoid<T>
{T acc = M.Zero;foreach (var i in array) acc = acc.Append(i);return acc;
}

注意到,类型 M 会根据 T 进行自动推导得到 Monoid<int>

这样我们就能做到在不需要修改 int 的定义的情况下为其实现接口。

Higher Kinded Polymorphism

Higher kinded polymorphism,又叫做 templated template,或者 generics on generics,这是一种高阶的多态。

举个例子,比如当我们需要表达一个类型是一个一阶泛型类型,且是实现了 ICollection<> 的容器之一时,我们可以写:

Copyvoid Foo<T>() where T : <>, ICollection<>, new();

有了这个特性我们可以轻而易举的实现 monads

例如我们想要做一个将 IEnumerable<> 中所有元素变成某种集合类型的时候,例如 ToList() 等,我们就不需要显式地实现每一种需要的类型的情况(例如 List<>):List<T> ToList(this IEnumerable<T> src)了。

我们只需要这么写:

CopyT<X> To<T, X>(this IEnumerable<X> xs) where T : <>, ICollection<>, new()
{var result = new T<X>();foreach (var x in xs) result.Add(x);return result;
}

当我们想要把一个 IEnumerable<int> x 转换成 List<int> 时,我们只需简单的调用:x.To<List<>>() 即可。

Simple Programs

该特性允许编写 C# 代码时,无需 Main 函数,直接像写脚本一样直接在文件中编写逻辑代码,以此简化编写少量代码时却需要书写大量样板代码的问题:

以前写代码:

Copynamespace Foo
{class Bar{static async Task Main(string[] args){await Task.Delay(1000);Console.WriteLine("Hello world!");}}
}

现在写代码:

Copyawait Task.Delay(1000);
Console.WriteLine("Hello world!");

Expression Blocks

该特性允许创建表达式块:

CopyFunc<int, int, bool> greaterThan = (a, b) => if (a > b) a else b;// true
greaterThan(5, 4);

因此有了以上特性,我们可以利用表达式实现更加复杂的东西。

后记

以上特性都是对代码布局和组成影响非常大的特性,并且不少特性几年前就已经被官方实现,但是因为存在尚未讨论解决的问题,迟迟没有发布进产品。

除此之外,还有几十个用于改进语言和方便用户使用等等的小特性也在未来的规划当中,此处不进行介绍。

未来的 C# 和今天的 C# 区别是很大的,作为一门多范式语言,C# 正在朝远离 Pure OOP 的方向渐行渐远,期待这门语言变得越来越好。

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

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

相关文章

Python--第1次平时作业

目录 一、单项选择题 二:填空题 三:大题代码 四:题目 五:测试代码 一、单项选择题 题号 1 2 3 4 5 6 7 8 9 10 答案 D C C D A B A B A C 题号 11 12 13 14 15 16 17 18 19 20 答案 C D D B C B A A D B 题号 21 22 23 2…

python二级考试怎么报名_全国计算机二级考什么 怎么报名

全国计算机二级是很多大学生都要参加的考试&#xff0c;计算机二级的证书含金量还是较高的&#xff0c;那么全国计算机二级主要考的科目有哪些&#xff0c;要怎么报名呢&#xff0c;小编对此进行了整理。计算机二级考哪些科目全国计算机二级可以考的科目如下表&#xff0c;考生…

如何构建基于.NET Core和云环境下的微服务技术体系?

这个内核用处不大&#xff0c;但.NET 内核却666随着业务需求的增长&#xff0c;我们现在开发非常大型和复杂的项目&#xff0c;需要更多时间来构建和部署。每当质量检查报告任何问题时&#xff0c;我们都需要对其进行调试或修复&#xff0c;然后部署整个代码。为了降低这些复杂…

UVA - 11059 Maximum Product-暴力枚举

输入n个元素组成的序列s,找出一个乘积最大的连续子序列&#xff0c;如果这个子序列不是整数&#xff0c;则输出0. 解题思路&#xff1a; 枚举起点和终点&#xff0c;把中间的数相乘&#xff0c;然后找到最大的结果。 代码如下&#xff1a; #include <iostream> using…

Python--第2次平时作业

目录 一、单项选择题 二、程序填空题 三、题目 四、测试代码 一、单项选择题 题号 1 2 3 4 5 6 7 8 9 10 答案 D D D D D D C D D C 题号 11 12 13 14 15 16 17 18 19 20 答案 D C B B D B C A B A 题号 21 22 23 24 25 …

好用的vp n推荐2020_哪个牌子的沐浴露好,2020年最新沐浴露选购测评,好用好闻易清洗沐浴露品牌推荐...

您好&#xff0c;感谢您关注并阅读本文。声明&#xff1a;本文系作者原创&#xff0c;未经作者授权不得转载、引用。如果您看完本文觉得对您有帮助&#xff0c;请点赞、收藏和关注&#xff0c;作者感激不尽。本文详细地介绍一下沐浴露使用方法和选购建议指南&#xff0c;以及沐…

【朝夕Net社区技术专刊】Core3.1 WebApi集群实战专题---WebApi环境搭建运行发布部署篇...

欢迎大家阅读《朝夕Net社区技术专刊》第1期我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为首期读者&#xff0c;文末福利不要错过哦&#xff01;本文通过5大部分进行解读&#xff1a…

《C++ Primer》1.51节练习

练习1.20 #include <iostream> #include "Sales_item.h" using namespace std;int main() {Sales_item book;cout << "请输入销售记录:" << endl;while (cin >> book) {cout << "ISBN,售出本数&#xff0c;销售额和平…

python schedule运行了一遍说没有任务_python-schedule模块(定时任务)基于官方文档总结...

一.模块安装pip3 install schedule二.常用的使用案例#基本格式#创建方法def func():print("方法")#创建定时schedule.every().seconds.do(func) #每秒运行一次#如果方法需要传参的话do(func,参数1)#开循环while True:schedule.run_pending()#如果值运行一次schedule.…

Python--第4次平时作业

目录 一、单项选择题 二、程序填空题 三、题目 四、测试代码 一、单项选择题 题号 1 2 3 4 5 6 7 8 9 10 答案 B D D C A B B C C C 题号 11 12 13 14 15 16 17 18 19 20 答案 C C B B C A A B A A 题号 21 22 23 24 25 …

【朝夕Net社区技术专刊】Core3.1 WebApi集群实战专题-Corre3.1WebApi配置集成日志/配置Swagger...

欢迎大家阅读《朝夕Net社区技术专刊》第2期我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为首期读者&#xff0c;文末福利不要错过哦&#xff01;本文通过3大部分进行解读&#xff1a…

python 16进制补零_Python输出16进制不带0x补零,整数转16进制,字符串转16进制

python输出16进制不带0x补零&#xff0c;整数转16进制&#xff0c;字符串转16进制在开发中&#xff0c;我们偶尔会遇到需要将数据通过控制台打印出来&#xff0c;以检查数据传输的准确性。例如调试服务端刚接到的二进制数据(里面包含很多非可见字符&#xff0c;也就是ascii码之…

一文读懂开源许可证异同

对开源许可证异同的对比并非源自担忧。对开源许可证进行比较并不容易&#xff0c;什么 copyleft 啦&#xff0c;什么宽松许可证啦&#xff0c;光 GNU 就有 GPL 2 和 GPL 3 之分&#xff0c;OSI 批准的许可证就有八十多个&#xff0c;而开源生态下存在了数百个许可证。对于我们这…

WARNING: Ignoring invalid distribution -ip

原因: 之前安装插件失败/中途退出&#xff0c;导致插件安装出现异常导致 解决方案: 进入你的项目里面,进入venv文件夹,进入Lib,进入site-packages,删除~ip开头的文件如图所示

根据后序和中序求二叉树的层序

题目描述&#xff1a;给出二叉树的后序和中序序列&#xff0c;输出二叉树的层序遍历序列。 题目分析&#xff1a;中序遍历为左根右&#xff0c;后序遍历为左右根&#xff0c;所以后序遍历的最后一个节点为根节点&#xff0c;在中序遍历上找出根节点的位置&#xff0c;将树分为…

mysql数据剪切到新表_6、MySQL核心DDL语句

命令类型服务器端命令获取命令帮助数据库管理查看数据库基础变量SQL组成创建修改删除表管理创建示例一示例二示例三一个常见的创建表结构的示例表修改改名表结构修改添加/删除字段修改字段键管理索引索引管理视图视图操作命令类型服务器端命令DDL&#xff1a;数据定义语言&…

pycharm里面下载pip(不用去官网)

注意:pycharm版本较低的话右侧有个"",一样的效果

C++ stringstream输入方式

在题目中&#xff0c;我们有时候会遇到不知道要输入多少个元素&#xff0c;这个时候我们要怎么读取呢&#xff1f; 采用stringstream输入方式&#xff0c;头文件为< sstream > 代码如下&#xff1a; #include <iostream> #include <cstring> #include <…