從未來看 C#

来源:https://www.cnblogs.com/hez2010/archive/2020/02/29/12385967.html
-Advertisement-
Play Games

前言 如今 C 雖然發展到了 8.0 版本,引入了諸多的函數式特性,但其實在 C 未來的規劃當中,還有很多足以大規模影響現有 C 代碼結構和組成的特性,本文中將會對就重要的特性進行介紹,並用代碼示例展示這些特性。 以下特性將會在 C 9.0、10.0 或者更高版本提供。 Records Record ...


前言

如今 C# 雖然發展到了 8.0 版本,引入了諸多的函數式特性,但其實在 C# 未來的規劃當中,還有很多足以大規模影響現有 C# 代碼結構和組成的特性,本文中將會對就重要的特性進行介紹,並用代碼示例展示這些特性。

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

Records

Records 是一種全新的簡化的 C# classstruct 的形式。

現在當我們需要聲明一個類型用來保存數據,並且支持數據的解構的話,需要像如下一樣寫出大量的樣板代碼:

class 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 之後,上面的樣板代碼只需簡化成一句話:

data class Point(double X, double Y);

並且 Records 支持數據的變換、解構和模式匹配:

var 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);

當然,recordimmutable 的,並且是可以合併(繼承)的,也可以標記為 sealed 或者 abstract

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

上面的這種 record 聲明方式是基於位置聲明的,即 Point(first, second)fisrt 所代表的第一個位置將成為 Xsecond 所代表的第二個位置將成為 Y

還有一種聲明方式是基於名稱的:

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

Discriminated Unions

Discriminated unions 又叫做 enum class,這是一種全新的類型聲明方式,顧名思義,是類型的 “枚舉”。

例如,我們需要定義形狀,形狀有矩形、三角形和圓形,以前我們需要先編寫一個 Shape 類,然後再創建 RectangleTriangleCircle 類繼承 Shape 類,現在只需要幾行就能完成,並且支持模式匹配和解構:

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

然後我們就可以使用啦:

var 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 的可空數據結構:

enum 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 Intersection Types

當我們想要表示一個對象是兩種類型其一時,將可以使用聯合類型來表達:

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

這在 Web API 中非常有用,當我們的介面可能返回錯誤的時候,我們不再需要將我們的數據用以下方式包含在一個統一的模式中:

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

我們將能夠做到,不依賴異常等流程處理的方式做到錯誤時返回錯誤信息,請求正常處理時返回真實所需的數據:

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

還有和類型,用來表示多個類型之和,我們此前在設計介面時,如果需要一個類型實現了多個介面,則需要定義一個新介面去實現之前的介面:

interface IA { ... }
interface IB { ... }
interface IAB : IA, IB { }

void Foo(IAB obj) { ... }

有了和類型之後,樣板代碼 IAB 將不再需要:

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

或者我們也可以這樣聲明新的類型:

type IAB = IA & IB;

Bottom Type

Bottom type 是一種特殊的類型 nevernever 類型是任何類型的子類,因此不存在該類型的子類。一個 never 類型的什麼都不表示。

Union types 帶來一個問題,就是我們有時候需要表達這個東西什麼都不是,那麼 never 將是一個非常合適的選擇:

type Foo = Bar | Baz | never;

另外,never 還有一個重要的用途:控制代碼流程,一個返回 never 的函數將結束調用者的邏輯,即這個函數不會返回:

void | 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

concept Monoid<T>
{
    // 加函數
    T Append(this T x, T y);
    // 零屬性
    static T Zero { get; }
}

然後我們可以為這個 concept 創建類型類的實例:

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

這樣我們就為 int 類型實現了 Monoid<int> 介面。

當我們想實現一個函數用來將一個 int 數組中的所有元素求和時,只需要:

public 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<> 的容器之一時,我們可以寫:

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

有了這個特性我們可以輕而易舉的實現 monads

例如我們想要做一個將 IEnumerable<> 中所有元素變成某種集合類型的時候,例如 ToList() 等,我們就不需要顯式地實現每一種需要的類型的情況(例如 List<>):List<T> ToList(this IEnumerable<T> src)了。

我們只需要這麼寫:

T<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 函數,直接像寫腳本一樣直接在文件中編寫邏輯代碼,以此簡化編寫少量代碼時卻需要書寫大量樣板代碼的問題:

以前寫代碼:

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

現在寫代碼:

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

Expression Blocks

該特性允許創建表達式塊:

Func<int, int, bool> greaterThan = (a, b) => if (a > b) a else b;

// true
greaterThan(5, 4);

因此有了以上特性,我們可以利用表達式實現更加複雜的東西。

後記

以上特性都是對代碼佈局和組成影響非常大的特性,並且不少特性幾年前就已經被官方實現,但是因為存在尚未討論解決的問題,遲遲沒有發佈進產品。

除此之外,還有幾十個用於改進語言和方便用戶使用等等的小特性也在未來的規劃當中,此處不進行介紹。

未來的 C# 和今天的 C# 區別是很大的,作為一門多範式語言,C# 正在朝遠離 Pure OOP 的方向漸行漸遠,期待這門語言變得越來越好。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇博文講解的知識點比較實用,但是,相關知識點太多,所以本人將內容分為上下兩冊, 那麼,本人就不多廢話,直接進入主題進行講解了! 說到“繼承”,大家可能都會想到我們日常中對於這個詞的定義:將先人的 物品 或 意志 傳承給後人,而後人也可以“擇優繼承”,併在先人的基礎上產生 新的物品 或 新的意志。 ...
  • 1、格式 (數據1,數據2,數據3,...) 定義元組使用小括弧,且逗號隔開各個數據,數據可以是不同的數據類型。 元組和列表的區別:元組存儲的數據不能修改 2、定義的類型 單數據元組和多數據元組 t1 = (1, 2) print(type(t1)) # tuple 多數據元組 t2 = (1,) ...
  • Title:ElasticSearch實戰系列四: ElasticSearch的聚合查詢基礎使用教程之度量(Metric)聚合 前言 在上上一篇中介紹了 "ElasticSearch實戰系列三: ElasticSearch的JAVA API使用教程" ,介紹了ElasticSearch Java A ...
  • [toc] 泛型: 首先,本人來介紹一下 什麼是泛型 : 泛型概述 : 是一種把類型明確的工作 推遲到創建對象 或者 調用方法的時候 才去 明確的特殊的類型 。 參數化類型 ,把類型當作參數一樣的傳遞。 通俗一點來講:泛型 是JAVA 中一種十分強大的機制,因為它能夠完成在 未知元素類型 的情況下對 ...
  • 在Java發展的里程碑上,有三個版本做出的改動,是革命性的 為什麼說是革命性的呢? 因為這三個版本所推出的有些新機制,在之後的Java框架開發、新類的產生等等中, 都被廣泛使用了。 那麼,這三個版本的JDK,都有哪些新特性呢? 現在,右轉哥就來帶你剖析這三個版本的JDK的新特性: [toc] 首先是 ...
  • xml配置 1.xml基本結構: 其中id是bean字元串,bean的唯一標識符,相當於對象名,class是bean類名的完全限定路徑 2.別名 起別名有兩種方式, 1.通過alias 2.通過bean中的name屬性 用bean中name更高級,可以起多個別名 IoC創建對象方式 1.通過無參構造 ...
  • 一、屬性(Property)作為類和結構的成員,是對欄位的一種封裝方式,實際上是一種特殊的方法,被稱為訪問器(Accessor),從而隱藏實現和驗證代碼,有助於提高欄位讀取和賦值的安全性和靈活性; 1.屬性訪問器包含兩種類型:用於讀取並返回值的get訪問器,用於賦值新值的set屬性訪問器;通常將欄位 ...
  • Lucene.Net Lucene.net是Lucene的.net移植版本,是一個開源的全文檢索引擎開發包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎。 Lucene.net是Apache軟體基金會贊助的開源項目,基於Apache License協議。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...