C# 7.3 版本有两个主要主题。 第一个主题提供使安全代码的性能与不安全代码的性能同样好的功能。 第二个主题提供对现有功能的增量改进。 此外,在此版本中添加了新的编译器选项。html
如下新增功能支持使安全代码得到更好的性能的主题:编程
ref
本地变量。stackalloc
数组上的初始值设定项。fixed
语句。对现有功能进行了如下加强:api
==
和 !=
。in
区分的参数的方法解析获得了改进。新的编译器选项为:数组
-publicsign
,用于启用程序集的开放源代码软件 (OSS) 签名。-pathmap
用于提供源目录的映射。
你应可以安全地编写性能与不安全代码同样好的 C# 代码。 安全代码可避免错误类,例如缓冲区溢出、杂散指针和其余内存访问错误。 这些新功能扩展了可验证安全代码的功能。努力使用安全结构编写更多代码。 这些功能使其更容易实现。安全
unsafe struct S { public fixed int myFixedField[10]; }
在早期版本的 C# 中,须要固定变量才能访问属于 myFixedField
的整数之一。 如今,如下代码进行编译,而不将变量 p
固定到单独的 fixed
语句中:ide
class C { static S s = new S(); unsafe public void M() { int p = s.myFixedField[5]; } }
变量 p
访问 myFixedField
中的一个元素。 无需声明单独的 int*
变量。 请注意,你仍然须要 unsafe
上下文。 在早期版本的 C# 中,须要声明第二个固定的指针:函数
class C { static S s = new S(); unsafe public void M() { fixed (int* ptr = s.myFixedField) { int p = ptr[5]; } } }
有关详细信息,请参阅有关 fixed
语句的文章。性能
ref
局部变量进行初始化后,可能会对其从新分配,以引用不一样的实例。 如下代码如今编译:
ref VeryLargeStruct refLocal = ref veryLargeStruct; // 初始化 refLocal = ref anotherVeryLargeStruct; // 从新分配后,反射引用不一样的存储。
有关详细信息,请参阅有关 ref
返回和 ref
局部变量以及 foreach
的文章。测试
var arr = new int[3] {1, 2, 3}; var arr2 = new int[] {1, 2, 3};
如今,可向使用 stackalloc
进行声明的数组应用同一语法:ui
int* pArr = stackalloc int[3] {1, 2, 3}; int* pArr2 = stackalloc int[] {1, 2, 3}; Span<int> arr = stackalloc [] {1, 2, 3};
有关详细信息,请参阅stackalloc
运算符一文。
fixed
语句支持有限的一组类型。 从 C# 7.3 开始,任何包含返回 ref T
或 ref readonly T
的 GetPinnableReference()
方法的类型均有可能为 fixed
。 添加此功能意味着 fixed
可与 System.Span<T> 和相关类型配合使用。
有关详细信息,请参阅语言参考中的 fixed
语句一文。
如今,能够将类型 System.Enum 或 System.Delegate 指定为类型参数的基类约束。
如今也能够使用新的 unmanaged
约束来指定类型参数必须为“非托管类型” 。 “非托管类型” 不是引用类型,且在任何嵌套级别都不包含任何引用类型。
有关详细信息,请参阅有关 where
泛型约束和类型参数的约束的文章。
将这些约束添加到现有类型是不兼容的更改。 封闭式泛型类型可能再也不知足这些新约束的要求。
如下功能提供了对语言中的功能的改进。 这些功能提高了在编写 C# 时的效率。
[field: SomeThingAboutFieldAttribute] public int SomeProperty { get; set; }
属性 SomeThingAboutFieldAttribute
应用于编译器生成的 SomeProperty
的支持字段。 有关详细信息,请参阅 C# 编程指南中的属性。
in
参数修饰符时,这两个方法将致使多义性:
static void M(S arg); static void M(in S arg);
如今,经过值(前面示例中的第一个)的重载比经过只读引用版本的重载更好。 若要使用只读引用参数调用版本,必须在调用方法前添加 in
修饰符。
有关详细信息,请参阅有关 in
参数修饰符的文章。
out
变量声明的语法进行了扩展,以包含字段初始值设定项、属性初始值设定项、构造函数初始值设定项和查询子句。 它容许使用如如下示例中所示的代码:
public class B { public B(int i, out int j) { j = i; } } public class D : B { public D(int i) : base(i, out var j) { Console.WriteLine($"The value of 'j' is {j}"); } }
在每一个版本中,对重载解析规则进行了更新,以解决多义方法调用具备“明显”选择的状况。此版本添加了三个新规则,以帮助编译器选取明显的选择:
this
实例接收器没法使用)包含未定义 this
的成员的正文(例如,静态成员),以及不能使用 this
的位置(例如,字段初始值设定项和构造函数初始值设定项)。你将注意到此更改,由于当你肯定哪一个方法更好时,你将发现多义方法重载具备更少的编译器错误。
-publicsign
编译器选项指示编译器使用公钥对程序集进行签名。 程序集被标记为已签名,但签名取自公钥。 此选项使你可以使用公钥在开放源代码项目中构建签名的程序集。
有关详细信息,请参阅 -publicsign 编译器选项一文。
-pathmap
编译器选项指示编译器将生成环境中的源路径替换为映射的源路径。 -pathmap
选项控制由编译器编写入 PDB 文件或为 CallerFilePathAttribute 编写的源路径。
有关详细信息,请参阅 -pathmap 编译器选项一文。