广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言完整特性详情
  • 937
分享到

C语言完整特性详情

2024-04-02 19:04:59 937人浏览 独家记忆
摘要

目录C# 10 完整特性介绍1、record struct2、sealed record ToString 方法3、struct 无参构造函数4、匿名对象的 with5、全局的 us

C# 10 完整特性介绍

前言:

C#使其拥有强如 Haskell 、Rust 的表达能力,不仅能提供从头到尾的跨程序集的静态类型支持,还能做到像动态类型语言那样的灵活。逻辑代码是类型的证明,只有类型系统强大了,代码编写起来才能更顺畅、更不容易出错。

1、record struct

首先自然是 record struct,解决了 record 只能给 class 而不能给 struct 用的问题:


record struct Point(int X, int Y);

用 record 定义 struct 的好处其实有很多,例如你无需重写 GetHashCode Equals 之类的方法了。

2、sealed record ToString 方法

之前 record 的 ToString 是不能修饰为 sealed 的,因此如果你继承了一个 record,相应的 ToString 行为也会被改变,因此这是个虚方法。

但是现在你可以把 record 里的 ToString 方法标记成 sealed,这样你的 ToString 方法就不会被重写了。

3、struct 无参构造函数

一直以来 struct 不支持无参构造函数,现在支持了:


struct Foo
{
    public int X;
    public Foo() { X = 1; }
}

但是使用的时候就要注意了,因为无参构造函数的存在使得 new struct() default(struct) 的语义不一样了,例如 new Foo().X == default(Foo).X 在上面这个例子中将会得出 false

4、匿名对象的 with

可以用 with 来根据已有的匿名对象创建新的匿名对象了:


var x = new { A = 1, B = 2 };
var y = x with { A = 3 };

这里 y.A 将会是 3 。

5、全局的 using

利用全局 using 可以给整个项目启用 usings,不再需要每个文件都写一份。比如你可以创建一个 Import.cs,然后里面写:


using System;
using i32 = System.Int32;

然后你整个项目都无需再 using System,并且可以用 i32 了。

6、文件范围的 namespace

这个比较简单,以前写 namespace 还得带一层大括号,以后如果一个文件里只有一个 namespace 的话,那直接在最上面这样写就行了:


namespace MyNamespace;

7、常量字符串插值

你可以给 const string 使用字符串插值了,非常方便:


const string x = "hello";
const string y = $"{x}, world!";

8、lambda 改进

这个改进可以说是非常大,我分多点介绍。

8.1. 支持 attributes

lambda 可以带 attribute 了:


f = [Foo] (x) => x; // 给 lambda 设置
f = [return: Foo] (x) => x; // 给 lambda 返回值设置
f = ([Foo] x) => x; // 给 lambda 参数设置

8.2. 支持指定返回值类型

此前 C# 的 lambda 返回值类型靠推导,C# 10 开始允许在参数列表最前面显示指定 lambda 类型了:


f = int () => 4;

8.3. 支持 ref 、in 、out 等修饰


f = ref int (ref int x) => ref x; // 返回一个参数的引用

8.4. 头等函数

函数可以隐式转换到 delegate,于是函数上升至头等函数:


void Foo() { Console.WriteLine("hello"); }
var x = Foo;
x(); // hello

8.5. 自然委托类型

lambda 现在会自动创建自然委托类型,于是不再需要写出类型了。


var f = () => 1; // Func<int>
var g = string (int x, string y) => $"{y}{x}"; // Func<int, string, string>
var h = "test".GetHashCode; // Func<int>

9、CallerArgumentExpression

现在,CallerArgumentExpression 这个 attribute 终于有用了。借助这个 attribute,编译器会自动填充调用参数的表达式字符串,例如:


void Foo(int value, [CallerArgumentExpression("value")] string? expression = null)
{
    Console.WriteLine(expression + " = " + value);
}

当你调用 Foo(4 + 5) 时,会输出 4 + 5 = 9。这对测试框架极其有用,因为你可以输出 assert 的原表达式了:


static void Assert(bool value, [CallerArgumentExpression("value")] string? expr = null)
{
    if (!value) throw new AssertFailureException(expr);
}

10、tuple 支持混合定义和使用

比如:


int y = 0;
(var x, y, var z) = (1, 2, 3);

于是 y 就变成 2 了,同时还创建了两个变量 x 和 z,分别是 1 和 3 。

11、接口支持抽象静态方法

这个特性将会在 .NET 6 作为 preview 特性放出,意味着默认是不启用的,需要设置 <LangVersion>preview</LangVersion> 和 <EnablePreviewFeatures>true</EnablePreviewFeatures>,然后引入一个官方的 nuget 包 System.Runtime.Experimental 来启用。

然后接口就可以声明抽象静态成员了,.net 的类型系统正式具备虚静态方法分发能力。

例如,你想定义一个可加而且有零的接口 IMonoid<T>:


interface IMonoid<T> where T : IMonoid<T>
{
    abstract static T Zero { get; }
    abstract static T operator+(T l, T r);
}

然后可以对其进行实现,例如这里的 MyInt:


public class MyInt : IMonoid<MyInt>
{
    public MyInt(int val) { Value = val; }

    public static MyInt Zero { get; } = new MyInt(0);
    public static MyInt operator+(MyInt l, MyInt r) => new MyInt(l.Value + r.Value);

    public int Value { get; }
}

然后就能写出一个方法对 IMoNIOd<T> 进行求和了,这里为了方便写成扩展方法:


public static class IMonoidExtensions
{
    public static T Sum<T>(this IEnumerable<T> t) where T : IMonoid<T>
    {
        var result = T.Zero;
        foreach (var i in t) result += i;
        return result;
    }
}

最后调用:


List<MyInt> list = new() { new(1), new(2), new(3) };
Console.WriteLine(list.Sum().Value); // 6

你可能会问为什么要引入一个 System.Runtime.Experimental,因为这个包里面包含了 .NET 基础类型的改进:给所有的基础类型都实现了相应的接口,比如给数值类型都实现了 INumber<T>,给可以加的东西都实现了 IAdditionOperators<TLeft, TRight, TResult> 等等,用起来将会非常方便,比如你想写一个函数,这个函数用来把能相加的东西加起来:


T Add<T>(T left, T right) where T : IAdditionOperators<T, T, T>
{
    return left + right;
}

就搞定了。

接口的静态抽象方法支持和未来 C# 将会加入的 shape 特性是相辅相成的,届时 C# 将利用 interface 和 shape 支持 Haskell 的 class、Rust 的 trait 那样的 type classes,将类型系统上升到一个新的层次。

12、泛型 attribute

是的你没有看错,C# 的 attributes 支持泛型了,不过 .NET 6 中将以预览特定放出,因此需要 <LangVersion>preview</LangVersion>:


class TestAttribute<T> : Attribute
{
    public T Data { get; }
    public TestAttribute(T data) { Data = data; }
}

然后你就能这么用了:


[Test<int>(3)]
[Test<float>(4.5f)]
[Test<string>("hello")]

13、允许在方法上指定 AsyncMethodBuilder

C# 10 将允许方法上使用 [AsyncMethodBuilder(...)] 来使用你自己实现的 async method builder,代替自带的 Task 或者 ValueTask 的异步方法构造器。这也有助于你自己实现零开销的异步方法。

14、line 指示器支持行列和范围

以前 #line 只能用来指定一个文件中的某一行,现在可以指定行列和范围了,这对写编译器和代码生成器的人非常有用:


#line (startLine, startChar) - (endLine, endChar) charOffset "fileName"

// 比如 #line (1, 1) - (2, 2) 3 "test.cs"

15、嵌套属性模式匹配改进

以前在匹配嵌套属性的时候需要这么写:


if (a is { X: { Y: { Z: 4 } } }) { ... }

现在只需要简单的:


if (a is { X.Y.Z: 4 }) { ... }

就可以了

15改进的字符串插值

以前 C# 的字符串插值是很粗暴的 string.FORMat,并且对于值类型参数来说会直接装箱,对于多个参数而言还会因此而分配一个数组(比如 string.Format("{} {}", a, b) 其实是 string.Format("{} {}", new object [] { (object)a, (object)b })),这很影响性能。现在字符串插值被改进了:


var x = 1;
Console.WriteLine($"hello, {x}");

会被编译成:


int x = 1;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(7, 1);
defaultInterpolatedStringHandler.AppendLiteral("hello, ");
defaultInterpolatedStringHandler.AppendFormatted(x);
Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());

上面这个 DefaultInterpolatedStringHandler 也可以借助 InterpolatedStringHandler 这个 attribute 替换成你自己实现的插值处理器,来决定要怎么进行插值。借助这些可以实现接近零开销的字符串插值。

Source Generator v2:

代码生成器在 C# 10 将会迎来 v2 版本,这个版本包含很多改进,包括强类型的代码构建器,以及增量编译的支持等等

到此这篇关于C# 10 完整特性详情的文章就介绍到这了,更多相关C# 10 完整特性内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言完整特性详情

本文链接: https://www.lsjlt.com/news/133777.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言完整特性详情
    目录C# 10 完整特性介绍1、record struct2、sealed record ToString 方法3、struct 无参构造函数4、匿名对象的 with5、全局的 us...
    99+
    2022-11-12
  • C语言 main 函数详情
    目录1、main()2、void main()3、int main(void)4、int main ()5、int main(int argc,char *argv[])前言: 但...
    99+
    2022-11-12
  • C语言 sizeof 函数详情
    目录一.sizeof 函数简介二.sizeof 函数实战一.sizeof 函数简介 在 C 语言中,char 字符串也是一种非常重要的数据类型,我们除了使用 sizeof 函数获取字...
    99+
    2022-11-12
  • C语言 sprintf 函数详情
    目录一.sprintf 函数简介二.sprintf 函数使用三.sprintf/fprintf/printf 函数区别一.sprintf 函数简介 sprintf 函数用于将格式化的...
    99+
    2022-11-12
  • C语言实现扫雷小游戏完整算法详解(附完整代码)
    目录前言1.算法基本思路2.算法详解1.初始化数组与打印数组2.设置雷3.排查与标记4.CountMine函数计算周围雷的个数 5.ExpandMine函数递归展开周围所有...
    99+
    2022-11-13
  • 用C语言完整实现2048游戏
    目录前言一、游戏思路二、游戏框架 1.菜单界面2.游戏主体1.初始化界面:2.随机生成初始数字3.实现移动4.增加新数字5.判定胜负6.游戏函数三、游戏运行四、所有代码总结 前言 游...
    99+
    2022-11-12
  • C语言 完整游戏项目推箱子详细代码
    话不多说 我们今天就来创造出属于我们自己的《推箱子》,GOGOGO!!! 直接开始吧 首先是我们用二维数组特定的数字描绘出这个地图 int cas = 0; int map[3...
    99+
    2022-11-12
  • C语言文件操作详情(一)
    目录前言:一、文件是什么二、文件类型三、文件缓冲区四、文件指针五、文件的打开和关闭前言: 文件操作重要吗? 当然重要:如果我们想让自己的程序拥有记忆功能,那就需要把要记忆的信息和数据...
    99+
    2022-11-13
  • C语言文件操作详情(二)
    目录前言一、文件的顺序读写函数fgetc和fputcfgets和fputsfscanf 和 fprintf对比一组函数fraed 和 fwriite二、文件的随机读写函数fseek ...
    99+
    2022-11-13
  • C语言队列和应用详情
    目录1.队列的原理2.队列的作用3.队列程序设计思路4.入列5.出列6.掌握队列程序编写7.队列的应用1.队列的原理 队列原理其实就像一个管道,如果我们不断往管道里面塞乒乓球,每个乒...
    99+
    2022-11-13
  • C语言实现扫雷附完整代码
    目录一、理清逻辑二、创建文件三、具体步骤1.打印菜单2.创建二维数组3.初始化二维数组并打印棋盘4.布置雷5.排查雷(内含判断胜负)四、完整代码五、待改进一、理清逻辑 我们先来看一下...
    99+
    2022-11-12
  • C语言完全平方整数的判断
    目录一、原理:二、函数三、分析:四、举例:总结一、原理: 利用 sqrt -- 求平方根 函数实现完全平方整数的判断。 二、函数          1.原形: #include ...
    99+
    2022-11-12
  • C语言实现扫雷OvO(完整代码)
    目录C语言实现扫雷OvO0.打印菜单1.初始化棋盘2.打印棋盘3.随机埋雷4.计算周围八个位置中雷的个数5.递归拓展非雷6.胜利条件7.输入坐标排雷8.完整代码8.1 game.h8...
    99+
    2022-11-13
  • C语言 完整游戏项目坦克大战详细代码
    话不多说 我们今天就来创造出属于我们自己的《坦克大战》,GOGOGO!!! 直接开始吧 这次的源码比较详细,我分了好几个cpp文件,思路更加的清晰,请耐心用心的观看 首先就是我们载...
    99+
    2022-11-12
  • C++语言有哪些特性
    本篇内容主要讲解“C++语言有哪些特性”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++语言有哪些特性”吧!Visual C++调试技术检查代码直到头晕眼花也没有发现错误,一运行程序就死机,只...
    99+
    2023-06-17
  • C语言中的内存管理详情
    目录1.malloc2.内存泄露3.内存池4.理论5.代码数据结构6.代码7.blk->begin8.总结内容提要: 大家写C程序时,手工申请过内存吗?每次需要存储空间时都向操...
    99+
    2022-11-13
  • C语言 函数缺省参数详情
    目录一.函数简介1.函数声明2.函数定义3.函数调用 4.函数形参和实参 二.函数缺省参数1.函数全缺省参数2.函数半缺省参数三.注意事项一.函数简介 1.函数声明 函数声明只是一个...
    99+
    2022-11-12
  • 怎么用C语言完整实现2048游戏
    这篇文章主要介绍怎么用C语言完整实现2048游戏,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、游戏思路程序开始时出现菜单,让玩家选择开始游戏或者退出游戏。玩家选择开始游戏后,出现棋盘,通过方向键选择移动的方向。移...
    99+
    2023-06-25
  • C语言实现整数逆序的情况解析
    逆序分两种情况。举个例子,情况① 输入1600,输出0061;情况② 输入1600,输出61. 情况① //情况① #include<stdio.h> void ma...
    99+
    2022-11-12
  • C语言通讯录管理系统完整代码
    本文实例为大家分享了C语言实现通讯录管理系统的具体代码,供大家参考,具体内容如下 设计内容: 设计一个通讯录管理系统,以实现以下功能:信息添加、查询、修改、删除、排序等功能。 设计要...
    99+
    2022-11-13
    C语言通讯录管理系统 C语言通讯录系统 C语言通讯录
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作