C#的泛型和匿名類型

一、C#的泛型簡介

????????泛型是一種允許你延遲編寫類或方法中的數據類型規范,直到你在實際使用時才替換為具體的數據類型簡單的說:泛型就是允許我們編寫能夠適用于任何數據類型的代碼,而無需為每種特定類型重寫相同的代碼】(T是類型參數,起到站位符的作用,編譯時被真正的類型替代)。

泛型的特性
序號泛型的特性說明
1泛型有助于開發人員最大限度的重用代碼、保護類型的安全性和提高性能
2開發人員可以創建自己的【泛型接口】【泛型類】【泛型方法】【泛型事件】【泛型委托】
泛型的優點
序號泛型的優點說明
1類型安全泛型確保我們在實際代碼中使用的都是正確的數據類型【可在編譯時捕獲到錯誤來確保類型安全】
2代碼重用泛型可以讓我們只用編寫一次通用代碼,就可用來處理各種不同數據類型(如各種方法重載)
3提高性能

泛型避免了不必要的類型轉換【沒有裝箱拆箱的消耗】,使得程序運行更快

裝箱和取消裝箱 - C# | Microsoft Learn

C#基礎:理解裝箱與拆箱

C# 裝箱和拆箱

4靈活性可以創建泛型接口、類、方法和委托內容,可處理我們選擇的任何類型
泛型的參數類型約束

《1》【泛型約束】主要是用于告知編譯器類型參數必須具備的功能在沒有任何約束的情況下,類型參數可以是任何類型。 編譯器只能假定?System.Object?的成員,它是任何 .NET 類型的最終基類);

《2》使用泛型約束的原因是【約束指定類型參數的功能和預期】(?聲明這些約束意味著你可以使用約束類型的操作和方法調用)

序號泛型約束說明
1where T : struct表示類型參數必須是不可為 null 的值類型;?由于所有值類型都具有可訪問的無參數構造函數(無論是聲明的還是隱式的),因此?struct?約束表示?new()?約束,并且不能與?new()?約束結合使用。?struct?約束也不能與?unmanaged?約束結合使用
2where T : class類型參數必須是引用類型。 此約束還應用于任何類、接口、委托或數組類型
3where T : class?類型參數必須是可為 null 或不可為 null 的引用類型。 此約束還應用于任何類、接口、委托或數組類型(包括記錄)
4where T : notnull類型參數必須是不可為 null 的類型。 參數可以是不可為 null 的引用類型,也可以是不可為 null 的值類型。
5where T : unmanaged類型參數必須是不可為 null 的非托管類型。?unmanaged?約束表示?struct?約束,且不能與?struct?約束或?new()?約束結合使用。
6where T : new()類型參數必須具有公共無參數構造函數。 與其他約束一起使用時,new()?約束必須最后指定。?new()?約束不能與?struct?和?unmanaged?約束結合使用。
7where T :<基類名>類型參數必須是指定的基類或派生自指定的基類。 在可為 null 的上下文中,T?必須是從指定基類派生的不可為 null 的引用類型。
8where T :<基類名>?類型參數必須是指定的基類或派生自指定的基類。 在可為 null 的上下文中,T?可以是從指定基類派生的可為 null 或不可為 null 的類型。
9where T :<接口名>類型參數必須是指定的接口或實現指定的接口。 可指定多個接口約束。 約束接口也可以是泛型。 在的可為 null 的上下文中,T?必須是實現指定接口的不可為 null 的類型
10where T :<接口名>?類型參數必須是指定的接口或實現指定的接口。 可指定多個接口約束。 約束接口也可以是泛型。 在可為 null 的上下文中,T?可以是可為 null 的引用類型、不可為 null 的引用類型或值類型。?T?不能是可為 null 的值類型
11where T : U為?T?提供的類型參數必須是為?U?提供的參數或派生自為?U?提供的參數。 在可為 null 的上下文中,如果?U?是不可為 null 的引用類型,T?必須是不可為 null 的引用類型。 如果?U?是可為 null 的引用類型,則?T?可以是可為 null 的引用類型,也可以是不可為 null 的引用類型
12where T : default重寫方法或提供顯式接口實現時,如果需要指定不受約束的類型參數,此約束可解決歧義。?default?約束表示基方法,但不包含?class?或?struct?約束。 有關詳細信息,請參閱default約束規范建議
13where T : allows ref struct此反約束聲明?T?的類型參數可以是?ref struct?類型。 該泛型類型或方法必須遵循?T?的任何實例的引用安全規則,因為它可能是?ref struct

某些約束是互斥的,而某些約束必須按指定順序排列:

《1》最多可應用?structclassclass?notnull?和?unmanaged?約束中的一個,則它必須是為該類型參數指定的第一個約束;

《2》基類約束(where T : Base?或?where T : Base?)不能與?structclassclass?notnull?或?unmanaged?約束中的任何一個結合使用;

《3》無論哪種形式,都最多只能應用一個基類約束。 如果想要支持可為 null 的基類型,請使用?Base?;

《4》不能將接口不可為 null 和可為 null 的形式命名為約束;

《5》new()?約束不能與?struct?或?unmanaged?約束結合使用。 如果指定?new()?約束,則它必須是該類型參數的最后一個約束。 反約束(如果適用)可以遵循?new()?約束;

《6》default?約束只能應用于替代或顯式接口實現。 它不能與?struct?或?class?約束結合使用;

《7》allows ref struct?反約束不能與?class?或?class??約束結合使用;

《8》allows ref struct?反約束必須遵循該類型參數的所有約束;

二、C#的泛型和匿名類型使用

?2.1、泛型類示例

//泛型類定義【基礎】
修飾符 class 類名<T>
{類代碼
}

????????泛型引入了類型參數用來充當數據類型的占位符,如下是一個可用于任何數據類型的泛型類和方法示例:

/// <summary>
/// 箱子泛型類
/// </summary>
/// <typeparam name="T">T是類型參數,可以是C#支持的所有數據類型(如:string,int,double,bool等)</typeparam>
internal class Box<T>
{public T Value { get; set; }public Box(T value){this.Value = value;    }public void Print(){Console.WriteLine($"【{Value}】屬于【{Value?.GetType()}】類型");}}//Class_end/// <summary>
/// 測試【箱子泛型類】的部分示例
/// </summary>
private static void TestBox()
{Console.WriteLine("---創建一個存放string數據的箱子---");Box<string> strBox = new Box<string>("字符串箱子");strBox.Print();Console.WriteLine("---創建一個存放Int數據的箱子---");Box<int> intBox = new Box<int>(666);intBox.Print();Console.WriteLine("---創建一個存放Double數據的箱子---");Box<double> doubleBox = new Box<double>(777.88888);doubleBox.Print();}

運行結果如下:【可以看到我們創建的泛型Box類可以創建各種數據類型的內容并打印出來】

2.2、泛型方法示例

 //泛型方法定義修飾符 void 方法名稱<類型參數>(類型參數 t){}//多泛型方法修飾符 void 方法名稱<類型參數1,類型參數2>(類型參數1 left, 類型參數2 Right){}//帶約束的泛型方法修飾符 類型參數 方法名稱<類型參數>(類型參數 left, 類型參數 Right) where 類型參數 : 約束{}
  //定義一個泛型方法,且實現泛型的數學運算internal class TestMethod{public static T Add<T>(T left, T Right) where T : INumber<T>{return left + Right;}}//Class_end//測試泛型方法private static void Test(){     int res = TestMethod.Add(5,6);Console.WriteLine($"5+6={res}");double res2 = TestMethod.Add(5.55, 6.32);Console.WriteLine($"5.55+6.32={res2}");}

運行結果如下:

2.3、泛型接口示例

//泛型接口定義
修飾符 interface I接口名稱<類型參數> 
{類型參數 字段名稱{ get; }void 方法名稱1(類型參數 t);  類型參數 方法名稱2(); 
}

????????使用泛型接口可在不同的類型中強制實施類型安全行為,且在不同類型之間強制實施一致行為,同時使代碼保持靈活且可重用。

System.Collections.Generic 命名空間(C#所有泛型集合的接口和類) | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/api/system.collections.generic?view=net-9.0????????IComparer<in T>接口表示具體的比較方法;實現創建PeopleComparer繼承IComparer泛型接口對People的年齡比較排序示例:

--定義兩個數據類型比較的接口IComparer
public interface IComparer<in T>
{int Compare(T? x, T? y);
}internal class People {public string? Name { get; set; }public int Age { get; set; }}//Class_end--繼承 IComparer接口并實現具體的比較方法
internal class PeopleComparer : IComparer<People>
{public int Compare(People? x, People? y){return x.Age.CompareTo(y.Age);}
}//Class_end//測試泛型接口
private static void TestGenericInterface()
{var Peoples = new List<People>{new People{Name="張三",Age=26 },new People{Name="李四",Age=29 },new People{Name="王五",Age=28 }};Peoples.Sort(new PeopleComparer());// Peoples.Sort(new PeopleComparer());foreach (var people in Peoples) { Console.WriteLine($"【{people.Name}】【{people.Age}】"); }
}
協變和逆變
序號協變和逆變說明
1協變

允許將更具體的類型(派生類型)分配給更常規的類型(基類型)

//示例【將更具體的string類型轉為object類】
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
2逆變

允許將更常規的類型(基類型)分配給更具體的類型(派生類型)

 //示例【將通用的object類型轉換為具體的stirng類型】Action<object> handleObject = obj => Console.WriteLine(obj);Action<string> handleString = handleObject;

1、使用泛型類型時,協變和逆變允許靈活性,尤其是在將一種類型分配給另一種類型時。 它們有助于確保某些方案中相關類型之間的兼容性。

2、讀取數據(如循環訪問集合)時,協變非常有用。 在寫入或處理數據(如將參數傳遞給方法)時,逆變非常有用。

協變和逆變 - C# | Microsoft Learn

2.4、泛型委托示例

namespace TestConsole
{//定義泛型委托public delegate T1 MyDel<T1,T2>(T2 t2);internal class TestDel{public TestDel(){//注冊委托1方法notify += MsgNotify;//注冊委托2方法sendMsg += SendMsg;}//聲明泛型委托1public MyDel<string,bool> notify;//編寫泛型委托1的需要調用的方法private string MsgNotify(bool status){string res = "";if (status){Console.WriteLine($"---泛型委托1執行:狀態是【{status}】---");res = "執行泛型委托1完成";}return res;}//聲明泛型委托2public MyDel<int, string> sendMsg;//編寫泛型委托2的需要調用的方法private int SendMsg(string msg){int res= 0;if (!string.IsNullOrEmpty(msg) && msg.Contains("sg")){var tmp = msg.Split("sg");Console.WriteLine($"---泛型委托2執行:【{tmp[1]}】開始發送到加密服務器---");res = 222;}return res;}}
}
 /// <summary>/// 測試泛型委托/// </summary>private static void TestGenericDelegate(){TestConsole.TestDel testDel= new TestConsole.TestDel();//使用委托1string res1 = testDel.notify(true);Console.WriteLine($"使用委托1的結果是【{res1}】\n");//使用委托2int res2 = testDel.sendMsg("sg你好,我是客戶端");Console.WriteLine($"使用委托2的結果是【{res2}】\n");}

?執行結果:

?2.5、匿名類型示例

匿名類型特點
序號匿名類型特點【匿名類型主要用于臨時數據結構,定義完整類是不必要的
1匿名類型是使用?new?運算符和對象初始值設定項創建的
2匿名類通常使用隱式類型變量var聲明
3它們通常用于語言集成查詢(LINQ)中,以返回對象的部分屬性

注意:

《1》匿名類型允許創建具有只讀屬性的對象,且不用定義類【編譯器為類型生成名稱,且該名稱在源碼中無法訪問;其中編譯器會自行確定每個屬性的類型】;

《2》匿名類型不能用作方法參數或返回類型;

《3》匿名類型只適用于方法范圍內創建臨時數據結構;

//創建匿名對象
var tmp = new { Name = "匿名類型", msg = "測試" };
Console.WriteLine($"{tmp.Name} {tmp.msg}");
//創建匿名對象數組 
var tmpObjArray = new[]{new { Name="AB床墊",Price=1600 },new { Name="鼠標",Price=169},new { Name="鍵盤",Price=199 },new { Name="顯示器",Price=699 },};//使用linq語法對內容進行過濾var filterRes = from obj in tmpObjArraywhere obj.Price >= 200select new { obj.Name, obj.Price };foreach (var obj in filterRes){Console.WriteLine($"【{obj.Name}】【{obj.Price}】");}
匿名類型和元組類型比較
序號功能 / 特點匿名類型元組類型
1類型引用類型 (class值類型 (struct
2自定義成員名稱支持支持????????
3析構不支持支持
4表達式樹支持支持不支持
在匿名類型和元組類型之間進行選擇 - .NET | Microsoft Learn

三、參考資料

泛型類型參數 - C# | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/generic-type-parametersNew 約束 - C# reference | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/new-constraint泛型類和方法 - C# | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/csharp/fundamentals/types/generics委托和事件簡介 - C# | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/csharp/delegates-overview

C# - 泛型:初學者的友好引導 - C# 高級教程 - W3schoolshttps://w3schools.tech/zh-cn/tutorial/csharp/csharp_generics?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909893.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909893.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909893.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

日語面試ai助手推薦:高效備考并應對日語面試難題

在準備日語面試的路上&#xff0c;你是否時常感到力不從心&#xff1f;每到模擬面試環節&#xff0c;總怕自己答非所問、用語不地道&#xff0c;或是緊張到腦子一片空白。查找資料時&#xff0c;面對海量的日語問答、面試范本和專業術語&#xff0c;常常分不清輕重緩急&#xf…

【63 Pandas+Pyecharts | 泡泡瑪特微博熱搜評論數據分析可視化】

文章目錄 &#x1f3f3;??&#x1f308; 1. 導入模塊&#x1f3f3;??&#x1f308; 2. Pandas數據處理2.1 讀取數據2.2 數據信息2.3 數據去重2.4 數據去空2.5 時間處理2.6 性別處理2.7 評論內容處理 &#x1f3f3;??&#x1f308; 3. Pyecharts數據可視化3.1 用戶評論IP分…

python-最長無重復子數組

最長無重復子數組 描述代碼實現 描述 給定一個長度為n的數組arr&#xff0c;返回arr的最長無重復元素子數組的長度&#xff0c;無重復指的是所有數字都不相同。 子數組是連續的&#xff0c;比如[1,3,5,7,9]的子數組有[1,3]&#xff0c;[3,5,7]等等&#xff0c;但是[1,3,7]不是…

探索 MySQL 緩存機制:提升數據庫讀取性能的有效策略

在現代應用中,數據庫的讀取性能是影響用戶體驗和系統響應速度的關鍵因素。當應用程序面臨高并發讀請求時,直接訪問磁盤的開銷會成為瓶頸。為了應對這一挑戰,MySQL 引入了多種緩存機制,旨在減少磁盤 I/O,加快數據檢索速度。 理解并合理利用這些緩存機制,是提升 MySQL 數據…

深度學習-164-MCP技術之開發本地MCP服務器和異步客戶端

文章目錄 1 概念1.1 MCP1.2 準備數據接口2 開發MCP服務器2.1 server.py2.1.1 @mcp.resource2.1.2 @mcp.tool()2.1.3 @mcp.prompt()2.2 調試模式啟動mcp-server2.2.1 資源2.2.2 工具2.2.3 提示詞3 開發MCP客戶端3.1 調用工具client_tool3.2 獲取提示client_prompt3.3 讀取資源cl…

第八十一篇 大數據開發基礎:隊列數據結構詳解與實戰應用(附生活化案例)

在大數據開發的龐大體系中&#xff0c;隊列&#xff08;Queue&#xff09; 作為基礎數據結構之一&#xff0c;其重要性不言而喻。它不僅是構建高效數據管道的核心組件&#xff0c;更是實現異步處理、流量削峰、任務調度的關鍵技術。本文將深入解析隊列的原理&#xff0c;結合生…

linux操作命令(最常用)

一、文件與目錄操作 命令作用常用參數示例ls列出目錄內容ls -l&#xff08;詳細列表&#xff09; ls -a&#xff08;顯示隱藏文件&#xff09;cd切換目錄cd ~&#xff08;回家目錄&#xff09; cd ..&#xff08;返回上級&#xff09;pwd顯示當前路徑-cp復制文件/目錄cp -r di…

22.react和next.js、SSR與CSR的比較

SSR 和 CSR 的區別 &#x1f538; 示例說明 SSR 流程&#xff08;Next.js 支持&#xff09;&#xff1a; 1. 用戶請求頁面 2. 服務端生成 HTML&#xff08;含內容&#xff09; 3. 瀏覽器收到渲染好的頁面 // SSR 頁面&#xff08;默認行為&#xff09; - app/page.tsx export…

全棧加速:FrankenPHP 架構原理與實戰案例

在當今云原生與微服務大行其道的時代&#xff0c;PHP 應用面臨著「冷啟動延遲高」「進程管理復雜」「性能瓶頸難以突破」等痛點。 FrankenPHP 正是為了解決這些問題而生&#xff1a;它將 Caddy 服務器與 PHP 運行時深度融合&#xff0c;內嵌 Let’s Encrypt 自動 HTTPS、支持 …

Android開發中的適配

目錄 一:分辨率適配 1.1概念 1.2關鍵策略 二:多尺寸適配 2.1概念 2.2關鍵策略 三:多平臺多版本適配 3.1Android系統版本迭代 3.2 關鍵策略 Android開發中的屏幕適配與多版本適配 在Android開發中,屏幕適配和多版本適配是確保應用在各種設備上都能良好運行和顯示的關鍵。這不…

【MySQL基礎篇】MySQL中的算術運算符和比較運算符

精選專欄鏈接 &#x1f517; MySQL技術筆記專欄Redis技術筆記專欄大模型搭建專欄Python學習筆記專欄深度學習算法專欄 歡迎訂閱&#xff0c;點贊&#xff0b;關注&#xff0c;每日精進1%&#xff0c;共攀技術高峰 更多內容持續更新中&#xff01;希望能給大家帶來幫助~ &…

FFmpeg推流實戰30秒速成

FFmpeg windows 7.1.1下載地址 FFmpeg 推流方法 FFmpeg 是一個強大的多媒體處理工具&#xff0c;支持將視頻和音頻推流到各種流媒體服務器&#xff08;如 RTMP、RTSP、HLS 等&#xff09;。以下是幾種常見的推流方法。 推流到 RTMP 服務器 RTMP&#xff08;Real-Time Messa…

74HC595功能介紹及代碼驅動

一、引腳描述 QA~QH(15,1~7腳):數據輸出引腳 QH1(9腳):移位寄存器串行數據輸出腳,當移位寄存器中的數據多余8位時,最先進入的那位被擠出去,一般級聯使用,接下一個74HC595 G(13腳):輸出使能引腳,低電平使能 RCK(12腳):存儲寄存器輸入數據使能引腳,上升沿時…

AntV G 入門教程

下面是 AntV?G&#xff08;以下簡稱 G&#xff09;的中文入門與核心 API 教程&#xff0c;涵蓋從畫布創建、圖形繪制到事件與動畫等常用方法&#xff0c;每個 API 均附帶完整示例代碼。示例引用自官方“Getting Started”指南 ([g.antv.antgroup.com][1])。 一、安裝與引入 #…

短視頻矩陣什么意思?

短視頻矩陣是指通過布局多個短視頻賬號&#xff0c;形成協同運營的賬號體系&#xff0c;以實現流量聚合、品牌曝光或商業變現的策略。其核心邏輯是利用不同賬號的定位、內容風格或受眾群體&#xff0c;構建互補的流量網絡&#xff0c;而非單一賬號的獨立運營。 核心特點與作用&…

Linux 日志查看和分析

Linux 日志是系統運行狀態的重要記錄&#xff0c;包含了系統啟動、服務運行、用戶操作、安全事件等關鍵信息&#xff0c;對于故障排查、安全審計和系統維護至關重要。 故障排查&#xff1a;定位系統崩潰、服務異常的根本原因&#xff08;如服務啟動失敗、硬件故障&#xff09;…

一篇文章快速學會HTML

一篇文章快速學會HTML 注&#xff1a;適合有一定編程基礎的來快速掌握HTML 超文本標記語言 超文本&#xff1a;文本&#xff0c;聲音&#xff0c;圖片&#xff0c;視頻&#xff0c;表格&#xff0c;鏈接 標記&#xff1a;許多的標簽組成 HTML頁面是運行到瀏覽器上的 HTML…

智能混合檢索DeepSearch

智能混合檢索 DeepSearch 是一款自主研發的大規模分布式搜索引擎&#xff0c;提供一站式智能搜索解決方案。系統內置多種行業專屬的查詢語義理解能力&#xff0c;融合語義 ORC 模型、文本向量模型、圖像/視頻向量模型、大語言模型&#xff08;LLM&#xff09;、分詞器以及機器學…

【Docker基礎】Docker鏡像管理:docker tag詳解

目錄 1 Docker鏡像標簽基礎概念 1.1 什么是Docker鏡像標簽 1.2 鏡像標識的三要素 2 docker tag命令詳解 2.1 命令基本語法 2.2 命令工作原理 2.3 常用操作示例 3 標簽管理的實踐示例 3.1 標簽命名規范 3.2 多標簽策略 3.3 latest標簽的合理使用 4 標簽與鏡像倉庫的…

AI時代個人IP的重塑與機遇 | 創客匠人

2025年作為AI應用爆發元年&#xff0c;正悄然改寫個人IP的打造邏輯。AI不會取代IP&#xff0c;卻會淘汰不懂得與AI共生的創作者。 AI重構IP運營的三大機遇 內容生產效率提升&#xff1a;傳統模式下需2-3天打磨的深度文章&#xff0c;AI輸入關鍵詞后半小時即可完成初稿&#xf…