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.mzph.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月改革机试后&#…