精品秘无码一区二区三区老师-精品秘一区二三区免费雷安-精品蜜桃秘一区二区三区-精品蜜桃秘一区二区三区粉嫩-精品蜜桃一区二区三区-精品蜜臀国产aⅴ一区二区三区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C#.NET Core 泛型(Generic)的好處和底層原理

freeflydom
2025年1月8日 11:11 本文熱度 329

簡介

泛型參考資料爛大街,基本資料不再贅述,比如泛型接口/委托/方法的使用,逆變與協變。

泛型好處有如下幾點

  1. 代碼重用
    算法重用,只需要預先定義好算法,排序,搜索,交換,比較等。任何類型都可以用同一套邏輯
  2. 類型安全
    編譯器保證不會將int傳給string
  3. 簡單清晰
    減少了類型轉換代碼
  4. 性能更強
    減少裝箱/拆箱,泛型算法更優異。

為什么說泛型性能更強?

主要在于裝箱帶來的托管堆分配問題以及性能損失

  1. 值類型裝箱會額外占用內存
            var a = new List<int>()
            {
                1,2, 3, 4
            };
            var b = new ArrayList()
            {
                1,2,3,4
            };

變量a:72kb

變量b:184kb

  1. 裝箱/拆箱會消耗額外的CPU
	public void ArrayTest()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		stopwatch.Start();
		ArrayList arrayList = new ArrayList();
		for (int i = 0; i < 10000000; i++)
		{
			arrayList.Add(i);
			_ = (int)arrayList[i];
		}
		stopwatch.Stop();
		Console.WriteLine($"array time is {stopwatch.ElapsedMilliseconds}");
	}
	public void ListTest()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		stopwatch.Start();
		List<int> list = new List<int>();
		for (int i = 0; i < 10000000; i++)
		{
			list.Add(i);
			_ = list[i];
		}
		stopwatch.Stop();
		Console.WriteLine($"list time is {stopwatch.ElapsedMilliseconds}");
	}

如此巨大的差異,無疑會造成GC的管理成本增加以及額外的CPU消耗。

思考一個問題,如果是引用類型的實參。差距還會如此之大嗎?
如果差距不大,那我們使用泛型的理由又是什么呢?

開放/封閉類型

CLR中有多種類型對象 ,比如引用類型,值類型,接口類型和委托類型,以及泛型類型。

根據創建行為,他們又被分為開放類型/封閉類型

為什么要說到這個? 泛型的一個有優點就是代碼復用,只要定義好算法。剩下的只要往里填就好了。比如List<>開放給任意實參,大家都可以復用同一套算法。

舉個例子

  1. 開放類型是指類型參數尚未被指定,他們不能被實例化 List<>,Dictionary<,>,interface 。它們只是搭建好了基礎框架,開放不同的實參
            Type it = typeof(ITest);
            Activator.CreateInstance(it);//創建失敗
            Type di = typeof(Dictionary<,>);
            Activator.CreateInstance(di);//創建失敗
  1. 封閉類型是指類型已經被指定,是可以被實例化 List<string>,String 就是封閉類型。它們只接受特定含義的實參
            Type li = typeof(List<string>);
            Activator.CreateInstance(li);//創建成功

代碼爆炸

所以當我們使用開放類型時,都會面臨一個問題。在JIT編譯階段,CLR會獲取泛型的IL,再尋找對應的實參替換,生成合適的本機代碼。
但這么做有一個缺點,要為每一種不同的泛型類型/方法組合生成,各種各種的本機代碼。這將明顯增加程序的Assembly,從而損害性能
CLR為了緩解該現象,做了一個特殊的優化:共享方法體

  1. 相同類型實參,共用一套方法
    如果一個Assembly中使用了List<Struct>另外一個Assembly也使用了List<Struct>
    那么CLR只會生成一套本機代碼。

  2. 引用類型實參,共用一套方法
    List<String>與List<Stream> 實參都是引用類型,它們的值都是托管堆上的指針引用。因此CLR對指針都可以用同一套方式來操作
    值類型就不行了,比如int與long. 一個占用4字節,一個占用8字節。占用的內存不長不一樣,導致無法用同一套邏輯來復用

眼見為實1

示例代碼
    internal class Program
    {
        static void Main(string[] args)
        {
            var a = new Test<string>();
            var b = new Test<Stream>();
            
            Debugger.Break();
        }
    }
    public class Test<T>
    {
        public void Add(T value)
        {
		
        }
        public void Remove(T value)
        {
        }
    }

變量a:

變量b

仔細觀察發現,它們的EEClass完全一致,它們的Add/Remove方法的MethodDesc也完全一直。這印證了上面的說法,引用類型實參引用同一套方法。

眼見為實2

點擊查看代碼
    internal class Program
    {
        static void Main(string[] args)
        {
            var a = new Test<int>();
            var b = new Test<long>();
            var c = new Test<MyStruct>();
            
            Debugger.Break();
        }
    }
    public class Test<T>
    {
        public void Add(T value)
        {
        }
        public void Remove(T value)
        {
        }
    }
    public struct MyStruct
    {
        public int Age;
    }

我們再把引用類型換為值類型,再看看它們的方法表。
變量a:

變量b:

變量c:

一眼就能看出,它們的MethodDesc完全不一樣。這說明在Assembly中。CLR為泛型生成了3套方法。

細心的朋友可能會發現,引用類型的實參變成了一個叫System.__Canon的類型。CLR 內部使用 System.__Canon 來給所有的引用類型做“占位符”使用
有興趣的小伙伴可以參考它的源碼:coreclr\System.Private.CoreLib\src\System__Canon.cs

為什么值類型無法共用同一套方法?

其實很好理解,引用類型的指針長度是固定的(32位4byte,64位8byte),而值類型的長度不一樣。導致值類型生成的底層匯編無法統一處理。因此值類型無法復用同一套方法。

眼見為實

?點擊查看代碼
    internal class Program
    {
        static void Main(string[] args)
        {
            var a = new Test<int>();
            a.Add(1);
            var b = new Test<long>();
            b.Add(1);
            var c = new Test<string>();
            c.Add("");
            var d = new Test<Stream>();
            d.Add(null);
            
            Debugger.Break();
        }
    }
    public class Test<T>
    {
        public void Add(T value)
        {
            var s = value;
        }
        public void Remove(T value)
        {
        }
    }
//變量a
00007FFBAF7B7435  mov         eax,dword ptr [rbp+58h]  
00007FFBAF7B7438  mov         dword ptr [rbp+2Ch],eax    //int 類型步長4 2ch
//變量b
00007FFBAF7B7FD7  mov         rax,qword ptr [rbp+58h]  
00007FFBAF7B7FDB  mov         qword ptr [rbp+28h],rax  //long 類型步長8 28h 匯編不一致
//變量c
00007FFBAF7B8087  mov         rax,qword ptr [rbp+58h]  
00007FFBAF7B808B  mov         qword ptr [rbp+28h],rax  // 28h
//變量d
00007FFBAF7B8087  mov         rax,qword ptr [rbp+58h]  
00007FFBAF7B808B  mov         qword ptr [rbp+28h],rax  // 28h 引用類型地址步長一致,匯編也一致。

泛型的數學計算

在.NET 7之前,如果我們要利用泛型進行數學運算。是無法實現的。只能通過dynamic來曲線救國

.NET 7中,引入了新的數學相關泛型接口,并提供了接口的默認實現。

https://learn.microsoft.com/zh-cn/dotnet/standard/generics/math

數學計算接口的底層實現

C#層:
相加的操作主要靠IAdditionOperators接口。

IL層:
+操作符被JIT編譯成了op_Addition抽象方法

對于int來說,會調用int的實現
System.Int32.System.Numerics.IAdditionOperators

對于long來說,會調用long的實現
System.Int64.System.Numerics.IAdditionOperators

從原理上來說很簡單,BCL實現了基本值類型的所有+-*/操作,只要在泛型中做好約束,JIT會自動調用相應的實現。

結論

泛型,用就完事了。就是要稍微注意(硬盤比程序員便宜多了)值類型泛型造成的代碼爆炸。

轉自https://www.cnblogs.com/lmy5215006/p/18529501


該文章在 2025/1/8 11:11:15 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 韩国b站mv免费的小妇人欧美 | 被十几个男人扒开腿猛戳电影 | 亚洲永久精品线路一二三四 | 伊人久久综在合线亚洲不卡 | 偷自拍国综合 | 久久精品亚洲精品国产欧美 | 亚洲午夜精品一区二区三区 | 综合亚洲桃色第一影院 | 国产免费毛卡片 | 久久人妻少妇嫩草av蜜桃 | 国产精品麻豆视频网站 | 91短视频在线观看免费最新 | 国产成人无码a区精油按摩 国产成人无码a区视频在线观看 | 久久精品动漫一区二区三区 | 日韩精品一区二区午夜成人版 | 国产精品久久久久久久久99热 | 日产精品卡二卡三卡四卡区 | 国产色情A片国语露对白 | 国产成人一区二区三区传媒 | 国产成人亚洲综合第一精品 | 国产成人一区久久 | 全色黄大色黄大片爽一次 | 国产薄丝脚交视 | 无码人妻久久一区二区三区免费 | 内射合集对白在线 | 成人国产精品日本在线 | 国产亚洲AV永久无码国产天堂 | 日韩插啊免费视频在线观看 | 日韩欧美一区二区三区不卡视频 | 国产成人无码av在线播放dvd | 女人与黑人搞视频 | 亚洲精品高清国产一久久 | 精品熟人妻一区二区三区四区不卡 | 久热这里只精品99re8久 | 毛片男人黑人巨大无码中文字幕无码 | 欧美国产精品va在线观看 | 亚洲综合精品八区 | 国产又色又爽又黄的视频免费观看 | 亚洲无码一区二区极品越南美女旗袍艺术照高清 | 亚洲AV无码区在线观看东京热 | 亚洲性久久久影院 |