日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【译】C#9的候选功能

發布時間:2023/12/4 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【译】C#9的候选功能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

通往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 <X>k__BackingField;

  • private readonly double <Y>k__BackingField;

  • private readonly double <Z>k__BackingField;

  • public double X {get {return <X>k__BackingField;}}

  • public double Y{get{return <Y>k__BackingField;}}

  • public double Z{get{return <Z>k__BackingField;}}


  • public Point3D(double X, double Y, double Z)

  • {

  • <X>k__BackingField = X;

  • <Y>k__BackingField = Y;

  • <Z>k__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 + EqualityComparer<double>.Default.GetHashCode(X)) * -1521134295 + EqualityComparer<double>.Default.GetHashCode(Y)) * -1521134295 + EqualityComparer<double>.Default.GetHashCode(Z);

  • }

  • }


  • Using Records:


  • public class Demo

  • {

  • public void CreatePoint()

  • {

  • Point3D point3D = new Point3D(1.0, 1.0, 1.0);

  • }

  • }

  • 新建議的特性“帶表達式”的記錄建議,你可以像下面這樣使用: varnewPoint3D=point3D.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#中已存在十多年,其他語言如(Scala,Kotlin)也有類似概念。

    支持構造函數和記錄的其他語言示例:F#?

    typeGreeter(name:string)=memberthis.SayHi()=printfn"Hi, %s"name

    Scala

  • class Greeter(name: String)

  • {

  • def SayHi() = println("Hi, " + name)

  • }

  • Kotlin

  • class 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 Eq<A>

  • {

  • bool Equal(A a, A b);

  • bool NotEqual(A a, A b);

  • }

  • 示例顯示接口和類型類直接的語法相似

  • interface Num<A>

  • {

  • A Add(A a, A b);

  • A Mult(A a, A b);

  • A Neg(A a);

  • }


  • struct NumInt : Num<int>

  • {

  • 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 Num<A>

  • {

  • A Add(A a, A b);

  • A Mult(A a, A b);

  • A Neg(A a);

  • }


  • instance NumInt : Num<int>

  • {

  • 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 SGroup<T>

  • {

  • static T operator +(T t1, T t2);

  • static T Zero {get;}

  • }

  • 這個聲明說如果類型在T上實現了一個+運算符,那么它可以是SGroup,并且是一個零靜態屬性。

  • public extension IntGroup of int: SGroup<int>

  • {

  • public static int Zero => 0;

  • }

  • 添加一個擴展:

  • public static AddAll<T>(T[] ts) where T: SGroup<T> // shape used as constraint

  • {

  • var result = T.Zero; // Making use of the shape's Zero property

  • foreach (var t in ts) { result += t; } // Making use of the shape's + 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 example

  • public 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基本且表現不同,因此無法與常量相關。

    原生大小的數字類型

    為本機引入一組新的本機類型(nint,nuint,nfloat,等)‘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#語言聲明固定大小的緩沖區。

    今天,用戶可以在不安全的環境中創建固定大小的緩沖區。然而,這需要用戶處理指針,手動執行邊界檢查,并且只支持一組有限的類型(bool,byte,char,short,int,long,sbyte,ushort,uint,ulong,float和double)。

    此功能將使固定大小的緩沖區安全,如下示例所示

    可以通過以下方式聲明一個安全的固定大小的緩沖區 publicfixedDXGI_RGBGammaCurve[1025];該聲明將編譯器轉化為內部表示,類似于以下內容

  • [FixedBuffer(typeof(DXGI_RGB), 1024)]

  • public ConsoleApp1.<Buffer>e__FixedBuffer_1024<DXGI_RGB> GammaCurve;


  • // Pack = 0 is the default packing and should result in indexable layout.

  • [CompilerGenerated, UnsafeValueType, StructLayout(LayoutKind.Sequential, Pack = 0)]

  • struct <Buffer>e__FixedBuffer_1024<T>

  • {

  • private T _e0;

  • private T _e1;

  • // _e2 ... _e1023

  • private T _e1024;

  • public ref T this[int index] => ref (uint)index <= 1024u ?

  • ref RefAdd<T>(ref _e0, index):

  • throw new IndexOutOfRange();

  • }

  • Uft8字符串文字

    它是關于定義一種新類型的Uft8String,如 System.UTF8String myUTF8string="Test 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/2337

    • https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-02-27.md

    概要

    你已經閱讀了第一個C# 9 的候選功能。正如你看到的,許多新功能受到其他編程語言或編程范例的啟發,而不是自我創新,但是好處是大多數候選功能在社區中得到了廣泛認可。

    原文鏈接

    注:翻譯原創

    總結

    以上是生活随笔為你收集整理的【译】C#9的候选功能的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。