[譯]C# 7系列,Part 9: ref structs ref結構

来源:https://www.cnblogs.com/wenhx/archive/2019/12/22/csharp-7-series-part-9-ref-structs.html
-Advertisement-
Play Games

原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/ 背景 在之前的文章中,我解釋了許多新的C#特性,每一個特性都是為了增強語言或者解決問題而引入的。具體來說,我解釋了值類型和引用類型 ...


原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/

背景

在之前的文章中,我解釋了許多新的C#特性,每一個特性都是為了增強語言或者解決問題而引入的。具體來說,我解釋了值類型和引用類型、按值傳遞參數、按引用傳遞參數、ref局部變數和ref返回結果以及in參數。這其中許多功能是為高性能場景設計的。

ref和in參數可以幫助避免複製值,從而減少記憶體分配。當你有分配在堆棧的局部變數作為方法的實際參數傳遞時,這麼做是有效率的的,在這種情況下,所有的分配都在堆棧上;不需要堆分配。

對於高性能和原生開發場景,你可能希望“僅限堆棧”類型始終停留在執行堆棧上,因此對這種類型的對象的操作只能發生在堆棧上,在作用域中公開給托管堆的任何對這種類型的外部引用都應該被禁止。

ref結構

ref struct是僅在堆棧上的值類型:

  • 表現一個順序結構的佈局;(譯註:可以理解為連續記憶體)
  • 只能在堆棧上使用。即用作方法參數和局部變數;
  • 不能是類或正常結構的靜態或實例成員;
  • 不能是非同步方法或lambda表達式的方法參數;
  • 不能動態綁定、裝箱、拆箱、包裝或轉換。

ref struct也被稱為嵌入式引用。

示例

下麵的代碼定義了一個ref結構。

public ref struct MyRefStruct
{
    public int MyIntValue1;
    public int MyIntValue2;

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override bool Equals(object obj) => throw new NotSupportedException();

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override int GetHashCode() => throw new NotSupportedException();

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override string ToString() => throw new NotSupportedException();
}

請註意,我已經覆蓋了從System.Object繼承的Equals、GetHashCode和ToString方法。因為ref結構不允許裝箱,所以你將無法調用這兩個(譯註:原文兩個,應該是三個)基方法。

你可以在方法參數或局部變數中使用MyRefStruct作為常規值類型,但不能在其他地方使用它。

 你也可以創建只讀ref結構,只需將readonly指令添加到ref結構聲明中即可。

public readonly ref struct MyRefStruct
{
    public readonly int MyIntValue1;
    public readonly int MyIntValue2;

    public MyRefStruct(int value1, int value2)
    {
        this.MyIntValue1 = value1;
        this.MyIntValue2 = value2;
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override bool Equals(object obj) => throw new NotSupportedException();

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override int GetHashCode() => throw new NotSupportedException();

    [EditorBrowsable(EditorBrowsableState.Never)]
    public override string ToString() => throw new NotSupportedException();
}

與常規只讀結構一樣,需要將所有實例欄位/屬性設置為只讀。

元數據

ref結構在C# 7.2中可用。此功能需要編譯器級別更改才能工作,以便與以前編譯器生成的程式集向後相容。編譯器會為ref結構聲明發出[Obsolete]和[IsByRefLike]特性。

如果任何舊的程式集引用了包含ref結構類型的庫,[Obsolete]屬性將影響並阻止代碼編譯。

下麵是為上面的ref結構聲明生成的IL。

.class public sequential ansi sealed beforefieldinit Demo.MyRefStruct
extends [System.Runtime]System.ValueType
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
        01 00 00 00
    )
.custom instance void [System.Runtime]System.ObsoleteAttribute::.ctor(string, bool) = (
        01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
        62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
        73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
        74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
        69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
        69 6c 65 72 2e 01 00 00
    )
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
        01 00 00 00
    )
// Fields
.field public initonly int32 MyIntValue1
.field public initonly int32 MyIntValue2
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
int32 value1,
int32 value2
        ) cil managed
    {
// Method begins at RVA 0x2090
// Code size 16 (0x10)
.maxstack 8
// (no C# code)
        IL_0000: nop
// this.MyIntValue1 = value1;
        IL_0001: ldarg.0
        IL_0002: ldarg.1
        IL_0003: stfld int32 Demo.MyRefStruct::MyIntValue1
// this.MyIntValue2 = value2;
        IL_0008: ldarg.0
        IL_0009: ldarg.2
        IL_000a: stfld int32 Demo.MyRefStruct::MyIntValue2
// (no C# code)
        IL_000f: ret
    } // end of method MyRefStruct::.ctor
.method public hidebysig virtual
instance bool Equals (
object obj
        ) cil managed
    {
// Method begins at RVA 0x20a1
// Code size 6 (0x6)
.maxstack 8
// throw new NotSupportedException();
        IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
        IL_0005: throw
    } // end of method MyRefStruct::Equals
.method public hidebysig virtual
instance int32 GetHashCode () cil managed
    {
.custom instance void [System.Runtime]System.ComponentModel.EditorBrowsableAttribute::.ctor(valuetype [System.Runtime]System.ComponentModel.EditorBrowsableState) = (
            01 00 01 00 00 00 00 00
        )
// Method begins at RVA 0x20a8
// Code size 6 (0x6)
.maxstack 8
// throw new NotSupportedException();
        IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
        IL_0005: throw
    } // end of method MyRefStruct::GetHashCode
.method public hidebysig virtual
instance string ToString () cil managed
    {
.custom instance void [System.Runtime]System.ComponentModel.EditorBrowsableAttribute::.ctor(valuetype [System.Runtime]System.ComponentModel.EditorBrowsableState) = (
            01 00 01 00 00 00 00 00
        )
// Method begins at RVA 0x20af
// Code size 6 (0x6)
.maxstack 8
// throw new NotSupportedException();
        IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
        IL_0005: throw
    } // end of method MyRefStruct::ToString
} // end of class Demo.MyRefStruct

Span<T>和Memory<T>

有了類ref類型的支持,現在就可以為所有連續記憶體訪問提供統一的類型。System.Span<T>表示記憶體的連續空間,可用於執行堆棧、托管堆和非托管堆的通用記憶體操作。

下麵是ReadOnlySpan<T>的一個簡單用法,用於去掉字元串的開始的空格。

internal class Program
{
    private static void Main(string[] args)
    {
        string text = "  I am using C# 7.2 Span<T>!";
        Console.WriteLine(TrimStart(text).ToArray());
    }

    private static ReadOnlySpan<char> TrimStart(ReadOnlySpan<char> text)
    {
        if (text.IsEmpty)
        {
            return text;
        }

        int i = 0;
        char c;

        while ((c = text[i]) == ' ')
        {
             i++;
        }

        return text.Slice(i);
    }
}

結論

C# 7.2為高性能場景添加了語言特性,併為低級別的原生開發和互操作性場景提供了效率。ref結構還可以與stackalloc、Span<T>、fixed buffers和Ranges(C# 7.3)一起用於生產力。

註意:要使用這個特性,需要Visual Studio 2017 15.5或更高版本。

 

系列文章:


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

-Advertisement-
Play Games
更多相關文章
  • 1.通過流的方式 1 public void WriteLog(string log) 2 { 3 StreamWriter stream; 4 string path = "D:/WriteLog/"; 5 if (!Directory.Exists(path)) 6 { 7 Directory. ...
  • 一、概念講解: 1、值類型: 包括:sbyte、short、int、long、float、double、decimal(以上值類型有符號) byte、ushort、uint、ulong(以上值類型無符號) bool、char 2、引用類型: 包括:對象類型、動態類型、字元串類型 二、具體區別: 1、 ...
  • 將表的行列倒置顯示(透視變換) 1)、創建數據表並添加數據 create table Score ( 學號 nvarchar(10) ,課程 nvarchar(10) ,成績 nvarchar(10) ); insert into Score(學號,課程,成績)values('0001','語文', ...
  • 在net Core3.1上基於winform實現依賴註入實例 [toc] 1.背景 net core3.1是微軟LTS長期3年支持版本,正式發佈於2019 12 03,並且在windows平臺上支持了Winfrom跟WPF桌面應用。本文介紹了使用Winform時的第一步,將應用層以及ORM涉及到的D ...
  • 本筆記摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,記錄一下學習過程以備後續查用。 一、委托類型的來由 在使用C語言的年代,整個項目中都充滿著針指的身影,那時候流行使用函數指針來創建回調函數,使用回調可以把函 ...
  • 這個場景跟《手寫Unity容器--極致簡陋版Unity容器》不同,這裡構造AndroidPhone的時候,AndroidPhone依賴於1個IPad 1、IPhone介面 2、AndroidPhone實現 3、IPad介面 4、IPad實現 5、容器--介面 6、容器--實現 7、調用 ...
  • WPF提供了一個更高級的模型,通過該模型可以只關註動畫的定義,而不必考慮它們的渲染方式。這個模型基於依賴項屬性基礎架構。本質上,WPF動畫只不過是在一段時間間隔內修染方式。這個模型基於依賴項屬性基礎架構。本質上,WPF動畫只不過是在一段時間間隔內修改依賴項屬性值的一種方式。 儘管目前WPF可為動畫使 ...
  • 聲明:參考於asp.net core 3.1 官網(以後不再說明) 本教程是系列教程中的第一個教程,介紹生成 ASP.NET Core Razor Pages Web 應用的基礎知識。 在本系列結束時,你將擁有一個管理電影資料庫的應用 環境:visual studio 2019. .ASP.NET ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...