C#泛型:高级静态语言的效率利器

文章目录

    • 引入
    • 类型约束
    • 子类泛型
    • 常用的泛型数据结构
    • 泛型委托

前文提要:

  • 💎超快速成,零基础掌握C#开发中最重要的概念
  • 💎抽丝剥茧,C#面向对象快速上手
  • 💎Winform,最友好的桌面GUI框架
  • 💎懂了委托,才算真正入门C#

引入

所谓泛型,就是创建一个函数,对所有数据类型都生效。最常见的例子就是运算符,毕竟1+1=21.0+1.0=2.0,足以看出+是对多种数据类型起作用的。

但是,如想创建一个函数add(int a, int b),那么输入add(1.0, 1.0)是肯定要报错的,VS直接就给标红了。

泛型的出现,就很好地解决了这个尴尬的问题

T add<T>(T a, T b) 
{dynamic d1 = a;dynamic d2 = b;return (T)(d1 + d2);
}Console.WriteLine(add<int>(1, 1));
Console.WriteLine(add<double>(1.0, 1.0));

上面代码中,T表示某种数据类型,在调用函数add时,根据add后面的<>加以声明。

但如果就此就写return a+b显然也是不行的,因为+这种运算符并没有对T进行重载,编辑器并不会允许两种未知的类型相加。

这个时候就需要用到dynamic,用来让编辑器放弃类型检查,将任何可能发生的错误都留给运行阶段。

最后,运行结果为

2
2

类型约束

dynamic用着确实爽,但后果就是责任自负,这玩意要是用在团队协作的场合,简直就是灾难,毕竟并非所有对象都可以驾驭加法。

所以,C#的泛型,是可以被约束的泛型,关键就是where,将上述代码写为

T add<T>(T a, T b) where T : struct{dynamic d1 = a;dynamic d2 = b;return (T)(d1 + d2);
}

where T : struct表示T必须是数值类型的一种,所以编译器的类型检查仍会发挥作用,在调用add时,如果T不是数值类型,就会报错。

C#一共有5种约束方案,列表如下

类别条件
structT必须是值类型
classT必须是引用类型
new()T必须有无参数的构造函数
基类名T必须是基类或派生自基类
接口名T必须是指定接口
裸类型

不同类型的约束,或相同类型不同种类的约束,一般是可以混用的,如果不能混用,编译器会提醒。比如struct几乎不能和其他类型混用。如果new()参与了约束,则放在最后。

子类泛型

除了函数可以采用泛型,类当然也可以,不仅可以,而且还能继承。

class MyList<T>
{public T[] a;public MyList(){}       //无参数的构造函数,用于继承public MyList(int n){a = new T[n];}public T this[int index]{get => a[index];set => a[index] = value;}}

MyList相当于是给数组套了一层壳,其构造函数并不存在什么难以理解的地方,唯一有些问题的可能是下面的索引器public T this[int index],这种写法可以实现方括号形式的索引。

可以测试一下

var a = new MyList<int>(5);
for (int i = 0; i < 5; i++)
{a[i] = i;Console.WriteLine(a[i]);
}

结果就不粘贴了,接下来新建一个子类

class MyStack<T> : MyList<T>
{public MyStack(int n){a = new T[n];}public T Pop(){T p = a[a.Length- 1];a = a[0..(a.Length-1)];return p;}
}

然后测试一下

var a = new MyStack<int>(3);
for (int i = 0; i < 3; i++)
{a[i] = i;
}for (int i = 0; i < 3; i++)
{Console.WriteLine(a.Pop());
}

结果为

2
1
0

常用的泛型数据结构

C#通过泛型定义了很多数据结构,例如在讲解switch...case时提到的字典

Dictionary<int, string> card = new Dictionary<int, string>
{{1,"A" },{11, "J" },{12, "Q" },{13, "K" }
};

这种<U, V>的写法,正是泛型的特点,其中U, V就是可以随意声明的变量。如果查看字典的类型参数,可以发现其定义方法是这样的

public class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, ... where TKey : notnull

考虑到本节并不是为了将面向对象,所以字典继承的那一大坨类就省略了,关键是where Tkey:notnull,也就是说,字典对键值对的要求只有一个,就是键不得为null

除了字典之外,还有一些常见的数据结构采用了泛型,列表如下,没事儿可以练习练习。

数据结构说明常用方法
List<T>泛型列表Add, Remove, RemoveAt
LinkedList<T>双端链表AddFirst, AddLast, RemoveFirst, RemoveLast
Queue<T>先进先出列表Enqueue, Dequeue
Stack<T>栈,先进后出Push, Pop

泛型委托

委托,是函数的函数;泛型,可以让函数的参数类型更加灵活,二者结合在一起,就是更加灵活的函数的函数,即泛型委托。

只要学过了泛型和委托,那么对泛型委托将毫无理解上的难度,回想前面定义的运算符委托

delegate int Op(int a, int b);

再回想定义泛型时的<T>,那么泛型委托可以非常简单地定义出来

delegate T Op<T>(T a, T b);

然后就可以根据委托,建立一个泛型函数

T add<T>(T a, T b)
{dynamic d1 = a;dynamic d2 = b;return (T)(d1 + d2);
}
var addTest = new Op<int>(add<int>);
//也可以省略add后的<int>,写成下面的形式
//var addTest = new Op<int>(add);
Console.WriteLine(addTest(3, 5));

运行之后控制台出现了8,就是这么简单。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/734491.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

启发式算法:遗传算法

文章目录 遗传算法-引例交叉变异遗传算法遗传算法流程遗传算法应用遗传算法-引例 在一代代演化过程中,父母扇贝的基因组合产生新扇贝,所以遗传算法会选择两个原有的扇贝,然后对这两个扇贝的染色体进行随机交叉形成新的扇贝。迭代演化也会造成基因突变,遗传算法让新产生扇贝…

Mysql索引底层数据结构

Mysql索引底层数据结构 一、数据结构1.1.索引的本质1.2.MySQl特点1.3.索引数据结构1.4.B-Tree结构1.5.BTree结构1.6.查看mysql文件页大小&#xff08;16K&#xff09;1.7.为什么mysql页文件默认16K&#xff1f;1.8.Hash结构 二、存储引擎2.1.InnoDB2.1.1.聚集索引2.1.2.为什么建…

Kubernetes 存储解释

文章目录 存储架构1、三个概念&#xff1a; pv &#xff0c; pvc &#xff0c;storageclass2、三种PV的访问模式3、三个重声明策略(reclaim policy)4、四个阶段(volumn phase)5、四个PV选择器6、五个可移植性建议7、六个生命周期 存储架构 有可能是最简单的Kubernetes存储解释…

力扣:数组篇

1、数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。 需要两点注意的是 数组下标都是从0开始的。数组内存空间的地址是连续的 因为数组的在内存空间的地址是连续的&#xff0c;所以我们在删除或者增添元素的时候&#xff0c;就难免要移动其他元素的地址。 …

centos7迁移龙蜥anolis8.8报错

1、报错 UPGRADE INHIBITED Upgrade has been inhibited due to the following problems:1. Inhibitor: Possible problems with remote login using root account#解决 sed -i s/#PermitRootLogin yes/PermitRootLogin yes/g /etc/ssh/sshd_configgrep…

【你也能从零基础学会网站开发】Web建站之javascript入门篇 JavaScript中的表达式、运算符、位运算、递增递减

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 JavaScript…

kali当中不同的python版本切换(超简单)

kali当中本身就是自带两个python版本的 配置 update-alternatives --install /usr/bin/python python /usr/bin/python2 100 update-alternatives --install /usr/bin/python python /usr/bin/python3 150 切换版本 update-alternatives --config python 0 1 2编号选择一个即可…

【MySQL篇】 MySQL基础学习

文章目录 前言基础数据类型DDL数据库操作查询数据库创建数据库删除数据库使用数据库 DDL表操作创建表查询表修改表删除 DML-增删改添加数据更改数据删除数据 DQL-查询基础查询条件查询聚合函数分组查询排序查询分页查询编写顺序 DML-用户及权限用户管理权限控制 函数字符串函数…

挑战杯 基于设深度学习的人脸性别年龄识别系统

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习机器视觉的…

【Frida实战】浅析Java层静态方法与实例方法的Hook技术及其应用

引言* 在移动安全研究领域&#xff0c;动态代码插桩工具Frida以其强大的功能和灵活的特性深受广大研究人员喜爱。本文将聚焦Frida在Java层面上对静态方法和实例方法的Hook过程&#xff0c;通过一个具体的Android应用示例&#xff0c;详细介绍其Hook原理和操作步骤。 Hook静态…

浅谈2024 年 AI 辅助研发趋势!

目录 ​编辑 引言 一、AI辅助研发现状 1. 技术发展 2. 工具集成 3. 应用场景 二、AI辅助研发趋势 1. 更高的自动化程度 2. 更高的智能化程度 3. 更多的领域应用 4. 更高的重视度 三、结论 四. 完结散花 悟已往之不谏&#xff0c;知来者犹可追 创作不易&#xff…

业务场景: arraylist我有1000条数据我现在要往每条数据后面加一个123,除了循环添加还有什么方法?

在Java中&#xff0c;如果您有一个ArrayList包含1000条数据&#xff0c;并且想要往每条数据后面添加一个固定的字符串&#xff08;比如"123"&#xff09;&#xff0c;那么循环遍历这个列表并逐个修改元素是最直接的方法。不过&#xff0c;如果您想要避免显式的for循环…

Golang 方法的接收器 receiver 指针和值的区别

一、如果receiver是指针类型 package mainimport "fmt"type Count struct {count int }func main() {c : Count{count: 0}c.incr()fmt.Println(c.count)c2 : &cc2.incr()fmt.Println(c2.count) }func (c *Count) incr() {c.count }//打印结果 1 2 incr 方法的 …

Windows系统Starting the Docker Engine 一直转圈解决方法

Windows系统Starting the Docker Engine 一直转圈解决方法 – 蓝队云 docker初始化安装时的WSL两个问题_unexpected wsl error-CSDN博客 docker desktop 因为某些原因无法打开报错wsl_docker desktop something went wrong-CSDN博客

【金三银四】刷刷八股吧,准备新的一周的到来

目录 前言1、Java中和equals有什么区别&#xff1f;2、String, StringBuffer, StringBuilder区别3、项目中对泛型的使用4、运行时数据区是怎样的&#xff1f;线程安全&#xff08;即线程私有&#xff09;的有哪些&#xff1f;5、对象实例、类信息、常量、静态变量分别在运行时数…

(南京观海微电子)——I3C协议介绍

特点 两线制总线&#xff1a;I2C仅使用两条线——串行数据线&#xff08;SDA&#xff09;和串行时钟线&#xff08;SCL&#xff09;进行通信&#xff0c;有效降低了连接复杂性。多主多从设备支持&#xff1a;I2C支持多个主设备和多个从设备连接到同一总线上。每个设备都有唯一…

题目 2036: 散列存储

题目描述: 给出了几个长度为n(n<20)的全排列&#xff0c;求某个全排列是否在上述的位置出现过。 代码: package lanqiao;import java.util.*;public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int m …

Python脚本,用于从MagicEden和HowRare API获取指定集合的拍卖列表和稀有度信息,并计算每个NFT的稀有度价格

一个Python脚本,用于从MagicEden和HowRare API获取给定集合的拍卖列表和稀有度信息,并计算每个NFT的稀有度价格。 代码的主要功能如下: 1. 导入所需的模块:`sys`,`time`,`requests`。 2. 定义了一个延迟时间`delay`,用于在每个API请求之间添加一定的延迟。 3. 定义了一个…

Mac安装oh-my-zsh

目录 命令下载 卸载命令 注意 命令下载 curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh 卸载命令 uninstall_oh_my_zsh 注意 终端init的时候并不会执行~/.bash_profile、~/.bashrc等脚本了&#xff0c; 这是因为其默认启动执行脚本…

017-$route、$router

$route、$router 1、$route2、$router 1、$route $route 对象表示当前的路由信息&#xff0c;包含了当前 URL 解析得到的信息。包含当前的路径&#xff0c;参数&#xff0c;query对象等。 使用场景&#xff1a; 获取路由传参&#xff1a;this.$route.query、this.$route.par…