天助网的网站,自己公司网站自己能做吗,linux部署wordpress,网站建设 国风网络通往C# 9 的漫长道路已经开始了#xff0c;这是世界上第一篇关于C# 9候选功能的文章。阅读完本文后#xff0c;你将希望为将来遇到新的C#挑战做好充分准备。 这篇文章基于#xff1a;C#语言版本计划 9.0 候选功能基于记录和模式匹配的表达式我一直在长时间等待这个功能。记录… 通往C# 9 的漫长道路已经开始了这是世界上第一篇关于C# 9候选功能的文章。阅读完本文后你将希望为将来遇到新的C#挑战做好充分准备。 这篇文章基于C#语言版本计划 9.0 候选功能基于记录和模式匹配的表达式我一直在长时间等待这个功能。记录是一种轻量级的不可变类型。它们是名义上的类型可能有方法、属性、运算符等并允许你比较结构相等。此外在默认情况下记录属性是只读的。记录可以是值类型或者引用类型。例如public class Point3D(double X, double Y, double Z);
public class Demo
{ public void CreatePoint() { var p new Point3D(1.0, 1.0, 1.0); }
} 上面的代码转换为public class Point3D { private readonly double Xk__BackingField; private readonly double Yk__BackingField; private readonly double Zk__BackingField; public double X {get {return Xk__BackingField;}} public double Y{get{return Yk__BackingField;}} public double Z{get{return Zk__BackingField;}} public Point3D(double X, double Y, double Z) { Xk__BackingField X; Yk__BackingField Y; Zk__BackingField Z; } public bool Equals(Point3D value) { return X value.X Y value.Y Z value.Z; } public override bool Equals(object value) { Point3D value2; return (value2 (value as Point3D)) ! null Equals(value2); } public override int GetHashCode() { return ((1717635750 * -1521134295 EqualityComparerdouble.Default.GetHashCode(X)) * -1521134295 EqualityComparerdouble.Default.GetHashCode(Y)) * -1521134295 EqualityComparerdouble.Default.GetHashCode(Z); } } Using Records: public class Demo { public void CreatePoint() { Point3D point3D new Point3D(1.0, 1.0, 1.0); } } 新建议的特性“带表达式”的记录建议你可以像下面这样使用 varnewPoint3Dpoint3D.With(x:42);创建一个新的点newPoint3D就像一个已存在的点point3D但是X的值变为了42。这种特性在模式匹配方面非常有效。我将在另一篇文章中介绍这个主题。F#中记录从MSDN中的例子复制的F#代码类型 Point3D{X:float; Y:float; Z:float}let evaluatePoint (point: Point3D) match point with | { X 0.0; Y 0.0; Z 0.0 } - printfn Point is at the origin. | { X xVal; Y 0.0; Z 0.0 } - printfn Point is on the x-axis. Value is %f. xVal | { X 0.0; Y yVal; Z 0.0 } - printfn Point is on the y-axis. Value is %f. yVal | { X 0.0; Y 0.0; Z zVal } - printfn Point is on the z-axis. Value is %f. zVal | { X xVal; Y yVal; Z zVal } - printfn Point is at (%f, %f, %f). xVal yVal zVal evaluatePoint { X 0.0; Y 0.0; Z 0.0 } evaluatePoint { X 100.0; Y 0.0; Z 0.0 } evaluatePoint { X 10.0; Y 0.0; Z -1.0 } 这段代码的输出如下Point is at the origin.Point is on the x-axis. Value is 100.000000.Point is at(10.000000, 0.000000, -1.000000).我想到的第一个问题是为什么我们需要记录使用结构不是更好吗为回答这个问题我从Reddit发表一个引用结构是需要一些准则来实现。你不必使他们不可变。不必实现值相等逻辑。不必使他们具有可比性。如果不这样做你将失去所有的便利但是编译器不会强制任何的这些约束记录类型由编译器实现这意味着你必须满足所有的条件并且不能出现错误。因此他们不仅可以节省大量的样板还可以消除一大堆潜在bugs。此外这个功能在F#中已存在十多年其他语言如ScalaKotlin也有类似概念。支持构造函数和记录的其他语言示例F# typeGreeter(name:string)memberthis.SayHi()printfnHi, %snameScalaclass Greeter(name: String) { def SayHi() println(Hi, name) } Kotlinclass Greeter(val name: String) { fun sayhi() { println(Hi, ${name}); } } 同时我们使用C#要编写这么长的代码public class Greeter{ private readonly string _name; public Greeter(string name) { _name name; } public void Greet() { Console.WriteLine($ Hello, {_name}); }}当这个功能完成后我们可以将C#代码减少到public class Greeter(name: string) { public void Greet() { Console.WriteLine($ Hello, {_name}); } } 更少的代码我喜欢它类型类Type Classes此特性的灵感来自Haskell她是我喜欢的功能。正如我之前在两年前我的文章中所说C#将实现更多函数式编程概念这就是FP概念之一。在函数式编程中类型类允许你在类型上添加一组操作但是不能实现它。由于实现是在其他地方完成的这是一种多态但是比面向对象编程语言中的经典类更灵活或ad-hoc。类型类和C#中的接口具有相似的用途但是它们的工作方式有所不同在某些情况下类型类更多的是直接使用因为它是直接在固定类中工作而不是继承层次结构的片段中。此功能最初与“扩展所有内容”特性一起被引入可以将它们组合在一起如下面Mads Torgersen示例中所示。我引用了官方提案中的一些文字一般来说“形状”声明非常类似于接口声明除了它几乎可以定义任何类型的长远包括静态成员可以通过扩展实现只能在某些地方用作类型Haskell 类型类例子class Eq a where () :: a - a - Bool (/) :: a - a - Bool Eq为类名而/是类中的操作类型“a”是类型“Eq”的实例Haskell示例作为通用C#接口interface Eq A { bool Equal(A a, A b); bool NotEqual(A a, A b); } Haskell示例作为C# 9 中的类型类shape是类型类中一个新的独特关键字shape EqA { bool Equal(A a, A b); bool NotEqual(A a, A b); } 示例显示接口和类型类直接的语法相似interface NumA { A Add(A a, A b); A Mult(A a, A b); A Neg(A a); } struct NumInt : Numint { public int Add(int a, int b) a b; public int Mult(int a, int b) a * b; public int Neg(int a) -a; } 使用C# 9 类型类shape NumA { A Add(A a, A b); A Mult(A a, A b); A Neg(A a); } instance NumInt : Numint { int Add(int a, int b) a b; int Mult(int a, int b) a * b; int Neg(int a) -a; } Mads Torgersen 示例重要信息shape不是一个类型。相反shape主要目的是用作通用约束显示类型参数以具有一个正确的shape。同时允许声明的主体可以使用shape。原始代码public shape SGroupT { static T operator (T t1, T t2); static T Zero {get;} } 这个声明说如果类型在T上实现了一个运算符那么它可以是SGroup并且是一个零静态属性。public extension IntGroup of int: SGroupint { public static int Zero 0; } 添加一个扩展public static AddAllT(T[] ts) where T: SGroupT // shape used as constraint { var result T.Zero; // Making use of the shapes Zero property foreach (var t in ts) { result t; } // Making use of the shapes operator return result; } 让我们使用一些证书调用AddAll方法int[] numbers { 5, 1, 9, 2, 3, 10, 8, 4, 7, 6 }; WriteLine(AddAll(numbers)); // infers T int 字典文字Dictionary Literals引入更简单的语法类创建初始化Dictionary对象而无需指定Dictionary类型名称或类型参数。Dictionary的类型参数使用用于数组类型推断的现有规则确定。// C# 1..8 var x new Dictionary string,int () { { foo, 4 }, { bar, 5 }}; // C# 9 var x [foo:4, bar: 5]; 此提议是C#中的字典工作更简单并删除冗余代码。此外值得一提的是在F#和Swift等其他编程语言中也使用了类似的字典语法。Params Span到目前为止在C#中不允许在结构声明中使用no-arg构造函数和字段初始值设定项。在C# 9 中将删除此限制。StackOverflow examplepublic struct Rational { private long numerator; private long denominator; public Rational(long num, long denom) { /* Todo: Find GCD etc. */ } public Rational(long num) { numerator num; denominator 1; } public Rational() // This is not allowed { numerator 0; denominator 1; } } 连接到 StackOverflow Example来自官提案的引文HaloFour 提交于2017年9月6日 提案 #099 改提议旨在销售阻止声明默认构造函数的语言限制。CLR已经完全支持具有默认构造函数的结构体并且C#支持使用它们。它们与常量完全无关并且由于该特征已经存在于CLR基本且表现不同因此无法与常量相关。原生大小的数字类型为本机引入一组新的本机类型nintnuintnfloat等‘n’为原生。计划为新数据类型的设计允许一个C#源文件使用32自然或64位存储具体取决于主机平台类型和编辑设置。本机类型取决于操作系统nint nativeInt 55; take 4 bytes when I compile in 32 Bit host. nint nativeInt 55; take 8 bytes when I compile in 64 Bit host with x64 compilation settings. 在xamarin中已存在类似概念。xamarin 原生类型固定大小的缓冲区这些提供了一种通用且安全的机制用于向C#语言声明固定大小的缓冲区。今天用户可以在不安全的环境中创建固定大小的缓冲区。然而这需要用户处理指针手动执行边界检查并且只支持一组有限的类型boolbytecharshortintlongsbyteushortuintulongfloat和double。此功能将使固定大小的缓冲区安全如下示例所示可以通过以下方式声明一个安全的固定大小的缓冲区 publicfixedDXGI_RGBGammaCurve[1025];该声明将编译器转化为内部表示类似于以下内容[FixedBuffer(typeof(DXGI_RGB), 1024)] public ConsoleApp1.Buffere__FixedBuffer_1024DXGI_RGB GammaCurve; // Pack 0 is the default packing and should result in indexable layout. [CompilerGenerated, UnsafeValueType, StructLayout(LayoutKind.Sequential, Pack 0)] struct Buffere__FixedBuffer_1024T { private T _e0; private T _e1; // _e2 ... _e1023 private T _e1024; public ref T this[int index] ref (uint)index 1024u ? ref RefAddT(ref _e0, index): throw new IndexOutOfRange(); } Uft8字符串文字它是关于定义一种新类型的Uft8String如 System.UTF8String myUTF8stringTest String;based(T)问题interface I1 { void M(int) { } } interface I2 { void M(short) { } } interface I3 { override void I1.M(int) { } } interface I4 : I3 { void M2() { base(I3).M(0) // What does this do? } } 棘手的部分在于M(short)和M(int)都适用于M(0)但查找规则也说如果我们在再次派生的接口中找到使用的成员我们忽略来自较少派生继承接口的成员。结合在查找期间未找到覆盖的规则在查看I3是我们发现第一件事是I2.M这是适用的这意味着I1.M 不会出现在使用成员列表中。 由于我们在上一次会议中得出结论目标类型中必须存在一个实现并且I2.M是唯一适用的成员所写的调用库(I3).M(0)是一个错误应为I2.M没有在I3中的一个实现更多信息https://github.com/dotnet/csharplang/issues/2337https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-02-27.md概要你已经阅读了第一个C# 9 的候选功能。正如你看到的许多新功能受到其他编程语言或编程范例的启发而不是自我创新但是好处是大多数候选功能在社区中得到了广泛认可。原文链接注翻译原创