C# Where 泛型約束

在C#中,Where關鍵字主要有兩種用途

1、在泛型約束中限制類型參數

2、在LINQ查詢中篩選數據

本文主要介紹where關鍵字在在泛型約束中的使用

? ? ? ?泛型定義中的?where?子句指定對用作泛型類型、方法、委托或本地函數中類型參數的參數類型的約束。通過使用?where?關鍵字和泛型約束,可以創建更安全、更靈活的泛型類和方法的實現。

使用的對象

Where可以對方法委托接口使用。

類的使用,例如C#中常用的List<T>

方法的使用,

public void MyFunc<T>() where T:struct

委托的使用

public delegate void MyDelete<T>() where T : class;

接口的使用

約束分類

約束

說明

where T : struct

T必須是值類型,如int,double等

where T : class

T必須是引用類型,如string,List<T>等

where T : new()

T必須有無參構造函數,即T參數可以通過使用new關鍵字創建實例。當與其他約束一起使用時,new() 約束必須最后指定。

where T : 基類

T 必須繼承自某個基類

where T : 接口

T 必須實現某個接口

where T : U

T 必須派生自 U

where T : struct

public class MyClass<T> where T : struct
{public T Value { get; set; }
}

例子:

// 只接受值類型的泛型方法
public class ValueCalculator<T> where T : struct
{public T Add(T a, T b){return (dynamic)a + (dynamic)b; // 簡單示例,實際中需要更安全的實現}
}// 使用示例
class Program
{static void Main(){var intCalc = new ValueCalculator<int>();Console.WriteLine(intCalc.Add(5, 3)); // 輸出 8// 下面這行會編譯錯誤,因為 string 是引用類型// var stringCalc = new ValueCalculator<string>();}
}

where T : class

public class MyClass<T> where T : class
{public T Value { get; set; }
}

例子?

public class Repository<T> where T : class, new()
{private List<T> items = new List<T>();public T CreateItem(){var newItem = new T(); // 可以實例化,因為有 new() 約束items.Add(newItem);return newItem;}public void DisplayCount(){Console.WriteLine($"Items count: {items.Count}");}
}// 使用示例
class Program
{class Customer{public string Name { get; set; }}static void Main(){var repo = new Repository<Customer>();var customer = repo.CreateItem();customer.Name = "John Doe";repo.DisplayCount(); // 輸出 Items count: 1}
}

where T : new()

public class Factory<T> where T : new()
{public T CreateInstance(){return new T();}
}

where T : 基類

public class AnimalShelter<T> where T : Animal
{public void Shelter(T animal){animal.Feed();}
}

where T : 接口

public class Sorter<T> where T : IComparable<T>
{public void Sort(T[] array){Array.Sort(array);}
}

?例子

using System;// 定義一個接口
public interface IDisplayable
{void Display();
}// 實現接口的類
public class Product : IDisplayable
{public string Name { get; set; }public void Display(){Console.WriteLine($"Product: {Name}");}
}// 使用 where 約束確保 T 實現 IDisplayable
public class DisplayManager<T> where T : IDisplayable
{public void Show(T item){item.Display(); // 安全調用,因為知道 T 有 Display 方法}
}// 使用示例
class Program
{static void Main(){var product = new Product { Name = "Laptop" };var manager = new DisplayManager<Product>();manager.Show(product);}
}

where T : U

public class DerivedContainer<T, U> where T : U
{// T 必須繼承自 U 或實現 U(如果 U 是接口)
}

?例子

public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some animal sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark!");}
}// 約束 T 必須繼承自 Animal
public class AnimalShelter<T> where T : Animal
{public void LetAnimalMakeSound(T animal){animal.MakeSound(); // 可以調用 Animal 的方法}
}// 使用示例
class Program
{static void Main(){var shelter = new AnimalShelter<Dog>();shelter.LetAnimalMakeSound(new Dog()); // 輸出 "Bark!"}
}

多重約束

可以為類型參數指定多個約束

需要注意的是:當與其他約束一起使用時,new() 約束必須最后指定。

public class MyClass<T> where T : class, IDisposable, new()
{}

多個類型參數的約束

對于多個類型參數,每個都可以有自己的約束:

 public class MyClass<TKey, TValue>where TKey : IComparable<TKey>where TValue : class,new(){}

約束的優點

1、增強類型安全?- 編譯器可以在編譯時捕獲類型不匹配的錯誤。

2、減少運行時轉換?- 避免不必要的類型檢查和轉換。

3、啟用更多操作?- 知道類型參數具有某些特性(如特定方法或構造函數)后,可以在泛型代碼中?使用這些特性。

4、不會對性能產生可測量的影響

總結:合理使用泛型約束可以顯著提高代碼質量和安全性,但應該避免過度使用導致不必要的復雜性。在大多數情況下,優點遠大于缺點,特別是在開發庫代碼或框架時。

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

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

相關文章

《MySQL:MySQL表的約束-主鍵/復合主鍵/唯一鍵/外鍵》

表的約束&#xff1a;表中一定要有各種約束&#xff0c;通過約束&#xff0c;讓未來插入數據庫表中的數據是符合預期的。約束本質是通過技術手段&#xff0c;倒逼程序員插入正確的數據。即&#xff0c;站在mysql的視角&#xff0c;凡是插入進來的數據&#xff0c;都是符合數據約…

Qt 創建QWidget的界面庫(DLL)

【1】新建一個qt庫項目 【2】在項目目錄圖標上右擊&#xff0c;選擇Add New... 【3】選擇模版&#xff1a;Qt->Qt設計師界面類&#xff0c;選擇Widget&#xff0c;填寫界面類的名稱、.h .cpp .ui名稱 【4】創建C調用接口&#xff08;默認是創建C調用接口&#xff09; #ifnd…

汽車免拆診斷案例 | 2011款雪鐵龍世嘉車刮水器偶爾自動工作

故障現象 一輛2011款雪鐵龍世嘉車&#xff0c;搭載1.6 L 發動機&#xff0c;累計行駛里程約為19.8萬km。車主反映&#xff0c;該車刮水器偶爾會自動工作&#xff0c;且前照燈偶爾會自動點亮。 故障診斷 接車后試車發現&#xff0c;除了上述故障現象以外&#xff0c;當用遙控器…

【Linux】NAT、代理服務、內網穿透

NAT、代理服務、內網穿透 一. NAT1. NAT 技術2. NAT IP 轉換過程3. NAPT 技術4. NAT 技術的缺陷 二. 代理服務器1. 正向代理2. 反向代理3. NAT 和代理服務器 內網穿透內網打洞 一. NAT NAT&#xff08;Network Address Translation&#xff0c;網絡地址轉換&#xff09;技術&a…

MobaXterm連接Ubuntu(SSH)

1.查看Ubuntu ip 打開終端,使用指令 ifconfig 由圖可知ip地址 2.MobaXterm進行SSH連接 點擊session,然后點擊ssh,最后輸入ubuntu IP地址以及用戶名

Spring Boot系列之使用Arthas Tunnel Server 進行遠程調試實踐

Spring Boot系列之使用Arthas Tunnel Server 進行遠程調試實踐 前言 在開發和運維 Java 應用的過程中&#xff0c;遠程診斷和調試是一個不可或缺的需求。尤其是當生產環境出現問題時&#xff0c;能夠快速定位并解決這些問題至關重要。Arthas 是阿里巴巴開源的一款強大的 Java…

圖像預處理-添加水印

一.ROI切割 類似裁剪圖片&#xff0c;但是原理是基于Numpy數組的切片操作(ROI數組切片是會修改原圖數據的)&#xff0c;也就是說這個“裁剪”不是為了保存“裁剪”部分&#xff0c;而是為了方便修改等處理。 import cv2 as cv import numpy as npimg cv.imread(../images/dem…

數據結構——八大排序算法

排序在生活中應用很多&#xff0c;對數據排序有按成績&#xff0c;商品價格&#xff0c;評論數量等標準來排序。 數據結構中有八大排序&#xff0c;插入、選擇、快速、歸并四類排序。 目錄 插入排序 直接插入排序 希爾排序 選擇排序 堆排序 冒泡排序 快速排序 hoare…

吃透LangChain(五):多模態輸入與自定義輸出

多模態數據輸入 這里我們演示如何將多模態輸入直接傳遞給模型。我們目前期望所有輸入都以與OpenAl 期望的格式相同的格式傳遞。對于支持多模態輸入的其他模型提供者&#xff0c;我們在類中添加了邏輯以轉換為預期格式。 在這個例子中&#xff0c;我們將要求模型描述一幅圖像。 …

【Rust 精進之路之第10篇-借用·規則】引用 (``, `mut`):安全、高效地訪問數據

系列: Rust 精進之路:構建可靠、高效軟件的底層邏輯 作者: 碼覺客 發布日期: 2025年4月20日 引言:所有權的“限制”與“變通”之道 在上一篇【所有權核心】中,我們揭示了 Rust 如何通過所有權規則和移動 (Move) 語義來保證內存安全,避免了垃圾回收器的同時,也防止了諸…

劍指Offer(數據結構與算法面試題精講)C++版——day16

劍指Offer&#xff08;數據結構與算法面試題精講&#xff09;C版——day16 題目一&#xff1a;序列化和反序列化二叉樹題目二&#xff1a;從根節點到葉節點的路徑數字之和題目三&#xff1a;向下的路徑節點值之和附錄&#xff1a;源碼gitee倉庫 題目一&#xff1a;序列化和反序…

OpenCV 模板與多個對象匹配方法詳解(繼OpenCV 模板匹配方法詳解)

文章目錄 前言1.導入庫2.圖片預處理3.輸出模板圖片的寬和高4.模板匹配5.獲取匹配結果中所有符合閾值的點的坐標5.1 threshold 0.9&#xff1a;5.2 loc np.where(res > threshold)&#xff1a; 6.遍歷所有匹配點6.1 loc 的結構回顧6.2 loc[::-1] 的作用6.2.1 為什么需要反轉…

產品經理學習過程

一&#xff1a;掃盲篇&#xff08;初始產品經理&#xff09; 階段1&#xff1a;了解產品經理 了解產品經理是做什么的、產品經理的分類、產品經理在實際工作中都會接觸什么樣的崗位、以及產品經理在實際工作中具體要做什么事情。 二&#xff1a;準備篇 階段2&#xff1a;工…

【消息隊列RocketMQ】一、RocketMQ入門核心概念與架構解析

在當今互聯網技術飛速發展的時代&#xff0c;分布式系統的架構設計愈發復雜。消息隊列作為分布式系統中重要的組件&#xff0c;在解耦應用、異步處理、削峰填谷等方面發揮著關鍵作用。RocketMQ 作為一款高性能、高可靠的分布式消息中間件&#xff0c;被廣泛應用于各類互聯網場景…

從“鏈主”到“全鏈”:供應鏈數字化轉型的底層邏輯

1. 制造業與供應鏈數字化轉型的必然性 1.1. 核心概念與戰略重要性 制造業的數字化轉型&#xff0c;是利用新一代數字技術&#xff08;如工業互聯網、人工智能、大數據、云計算、邊緣計算等&#xff09;對制造業的整體價值鏈進行根本性重塑的過程。這不僅涉及技術的應用&#…

x-ui重新申請ssl證書失敗

由于某些需要我們重新申請ssl證書&#xff0c;x-ui自動化腳本不能強制更新&#xff0c;根據x-ui倉庫源碼&#xff1a; https://github.com/vaxilu/x-ui/blob/main/x-ui.sh 在申請ssl證書的地方稍作修改&#xff0c;得到&#xff0c;運行下面的腳本就可以重新申請ssl證書&#…

Java NIO Java 虛擬線程(微線程)與 Go 協程的運行原理不同 為何Go 能在低配機器上承接10萬 Websocket 協議連接

什么是Java NIO&#xff1f; Java NIO&#xff08;New Input/Output&#xff09; 是Java 1.4&#xff08;2002年&#xff09;引入的一種非阻塞、面向緩沖區的輸入輸出框架&#xff0c;旨在提升Java在高性能和高并發場景下的I/O處理能力。它相比傳統的 Java IO&#xff08;java…

go環境安裝mac

下載go安裝包&#xff1a;https://golang.google.cn/dl/ 找到對應自己環境的版本下載。 注意有二進制的包&#xff0c;也有圖形界面安裝的包。圖形界面直接傻瓜式點就行了。 二進制的按照下面操作&#xff1a; 1、下載二進制包。 2、將下載的二進制包解壓至 /usr/local目錄…

LVGL源碼(9):學會控件的使用(自定義彈窗)

LVGL版本&#xff1a;8.3 LVGL的控件各式各樣&#xff0c;每種控件都有自己的一些特性&#xff0c;當我們想要使用一個LVGL控件時&#xff0c;我們首先可以通過官網去了解控件的一些基本特性&#xff0c;官網鏈接如下&#xff1a; LVGL Basics — LVGL documentation&#xf…

《軟件設計師》復習筆記(1)——考試介紹【新】

目錄 一、考試介紹 證書價值 考試要求 二、【新】計算機與軟件工程知識 三、軟件設計 一、考試介紹 >考試科目>考題形式>考試時長>合格標準計算機與軟件工程知識75道單選題&#xff08;每題1分&#xff0c;總分75分&#xff09;2023年11月改革機試后&#…