[C#基础] 泛型
为什么泛型?
在泛型中,最重要的应用便是集合类,因此我们模拟一个简单的集合类

对于上述示例,可以有如下应用

从上可看出,自定义的代码太丑陋了,只能用于string类型。 当然我们可以用object作为参数类型,然而深入分析则会发现有些问题仍然存在,这种方式还会有性能问题,值类型Add到集合时必然存在装箱,而将元素赋值给一个值类型变量时,又存在拆箱,这样的性能损失在操作大量元素的时候格外明显!
正是这个问题的存在,所以泛型登场了。重新实现MyArray类型,体验泛型的好处

自定义的泛型集合类,能够轻松实现对任意类型的管理和操作
泛型基础
泛型类
上述代码已经演示了泛型类,我们发现定义一个泛型类和定义一个非泛型类并没有太大的区别,主要的不同在于,类型参数化。类型定义时,将指定类型形参(通常用T表示),紧随类名,并包含在<>内。
泛型类的声明

上述代码将创建一个值类型对象myArr,并调用构造器完成初始化。int作为T的类型实参在JIT编译时所有T将被替换为int,因此_items内部数组将保存int类型的数组元素。
泛型类型的声明也可以包括多个类型形参,如

约束
约束,指在定义泛型时,对于能够实例化类型参数的类型所做的限制,这种限制能保证类型参数在一定的目标范围。
约束通过where字句来实现,多个约束之间用逗号隔开,通常情况下,在设计泛型类或泛型方法时,如果要实现一个object类不支持的任何方法,则需要对参数类型进行约束。

约束主要包括,构造器约束,值类型约束,引用类型约束,基类约束,接口约束,具体情况为:
- T:new(),表示类型参数必须具有公共无参构造函数,有多个约束存在时,必须把new()放在最后面。
- T:struct,表示类型参数必须是值类型。
- T:class,表示类型参数必须是引用类型。
- T:基类名,表示类型参数必须是基类或及其派生类。但是不能既指定基类约束又指定class
- T:接口名,表示类型参数必须是指定的接口,或实现了该接口的接口,可以同时定义多个接口约束,约束接口也可以是泛型的。
泛型方法
泛型方法可以存在于泛型类,也可以存在于非泛型类中
可以将类型参数作为某个方法的参数,返回值或者局部变量,该类型参数可能并不被整个类所需要,而更明确的用于某个方法,例如

方法重载

由此可见,泛型方法可以以类型参数形成重载。
然而泛型方法重载,存在值得注意的问题:由于类型参数在编译期并不确定,所以重载检查是在实例方法被调用时才发生,而不是在泛型类本身编译时检查,例如下面的泛型类可以安全通过编译

然而在调用时,将会给出调用不明确的编译错误

类型推断
泛型方法的调用,可以用更简洁的方式来实现,例如
myArr.ShowInfo("s");
这种机制由编译器支持,称为:类型推断。表示编译器在调用时根据方法参数来推断类型参数,从而决定使用的泛型方法。因此,这种方式不适用于没有参数的方法,同时编译器会优先选择显示的匹配调用,例如上面所示,将会调用非泛型ShowInfo方法,而非泛型方法ShowInfo<TData>方法,除非以显示方式调用来是实现。
myArr.ShowInfo<string>("s");
泛型接口
泛型接口允许我们编写参数和接口成员返回类型是泛型类型参数的接口
如下代码声明了一个泛型接口,泛型类Sample实现了这个泛型接口,main实例化了两个泛型类,一个int 一个string
class Program
{
static void Main(string[] args)
{
var testInt = new Sample<int>();
var testString = new Sample<string>();
Console.WriteLine(testInt.ReturnIt());
Console.WriteLine(testString.ReturnIt("aa")); }
}
interface IMyIfc<T>
{
T ReturnIt(T value);
}
class Sample<T> : IMyIfc<T>
{ public T ReturnIt(T value)
{
throw new NotImplementedException();
}
}
使用泛型接口的示例
如下示例演示了泛型接口的两个额外的能力
- 与其他泛型相似,实现不同类型参数的泛型接口是不同的接口
- 可以在非泛型类中实现泛型接口
例如下面的代码与前面的相似,但在这里Sample是个非泛型类,它实现了两个IMyIfc实例,一个int类型,一个string类型
class Sample : IMyIfc<int>, IMyIfc<string>
{ public int ReturnIt(int value) //实现int类型
{
throw new NotImplementedException();
} public string ReturnIt(string value) //实现string类型
{
throw new NotImplementedException();
}
}
泛型接口的实现必须唯一
实现泛型接口时,必须保证类型实参组合不会在类型中产生两个重复的接口

典型的泛型接口

泛型委托
泛型委托支持在返回值和参数上应用类型参数,泛型委托能够有效避免值类型实例传给一个回调方法时的装箱处理。
如下代码实现了一个泛型委托的简单示例
class Program
{
//声明一个泛型委托
public delegate string MyGenericDelegate<T>(T t); //实现两个测试方法
public static string GetString(string s)
{
return s;
} public static string GetInt(int i)
{
return i.ToString();
}
static void Main(string[] args)
{
//实现测试代码
MyGenericDelegate<string> myStrDel = new MyGenericDelegate<string>(GetString);
Console.WriteLine(myStrDel("aa")); MyGenericDelegate<int> myIntDel=new MyGenericDelegate<int>(GetInt);
Console.WriteLine(myIntDel()); }
}
实用Func泛型委托的示例
class Sample
{
public static string PringStr(string s1, string s2)
{
return s1 + s2;
}
}
static void Main(string[] args)
{
var myDel = new Func<string, string, string>(Sample.PringStr);
Console.WriteLine(myDel("","")); }
[C#基础] 泛型的更多相关文章
- Java17-java语法基础——泛型
Java18-java语法基础——泛型 一.泛型概念和作用 1.泛型概念: 泛型是JavaSE1.5的新特性,泛型的本质是参数化类型,也就是说,所操作的数据类型被指定为一个参数.这种参数类型可以用在类 ...
- 一天一个Java基础——泛型
这学期的新课——设计模式,由我仰慕已久的老师传授,可惜思维过快,第一节就被老师挑中上去敲代码,自此在心里烙下了阴影,都是Java基础欠下的债 这学期的新课——算法设计与分析,虽老师不爱与同学互动式的讲 ...
- Java 基础 -- 泛型、集合、IO、反射
package com.java.map.test; import java.util.ArrayList; import java.util.Collection; import java.util ...
- [c#基础]泛型集合的自定义类型排序
引用 最近总有种感觉,自己复习的进度总被项目中的问题给耽搁了,项目中遇到的问题,不总结又不行,只能将复习基础方面的东西放后再放后.一直没研究过太深奥的东西,过去一年一直在基础上打转,写代码,反编译,不 ...
- java基础-泛型3
浏览以下内容前,请点击并阅读 声明 8 类型擦除 为实现泛型,java编译器进行如下操作进行类型擦除: 如果类型参数有限制则替换为限制的类型,如果没有则替换为Object类,变成普通的类,接口和方法. ...
- java基础 泛型
泛型的存在,是为了使用不确定的类型. 为什么有泛型? 1. 为了提高安全 2. 提高代码的重用率 (自动 装箱,拆箱功能) 一切好处看代码: package test1; import java.la ...
- java基础-泛型2
浏览以下内容前,请点击并阅读 声明 6 类型推测 java编译器能够检查所有的方法调用和对应的声明来决定类型的实参,即类型推测,类型的推测算法推测满足所有参数的最具体类型,如下例所示: //泛型方法的 ...
- java基础-泛型1
浏览以下内容前,请点击并阅读 声明 泛型的使用能使类型名称作为类或者接口定义中的参数,就像一般的参数一样,使得定义的类型通用性更强. 泛型的优势: 编译具有严格的类型检查 java编译器对于泛型代码的 ...
- Spring基础—— 泛型依赖注入
一.为了更加快捷的开发,为了更少的配置,特别是针对 Web 环境的开发,从 Spring 4.0 之后,Spring 引入了 泛型依赖注入. 二.泛型依赖注入:子类之间的依赖关系由其父类泛型以及父类之 ...
随机推荐
- linux下的软件包安装
linux下安装软件包有两种方法:源文件编译安装(source)和 rpm 安装. 1.源文件包安装的通用方法. 一般安装源代码的程序你得要看它的README,一般在它的目录下都有的. 01.配置: ...
- 初探 FFT/DFT
有用的学习链接&书籍 傅立叶变化-维基百科 离散傅立叶变化-维基百科·长整数与多项式乘法 维基百科看英文的更多内容&有趣的图 快速傅立叶变化-百度百科,注意其中的图! 组合数学(第4版 ...
- java调用163邮箱发送邮件
1:注册一个163邮箱,http://mail.163.com 调用发送邮件代码,查询smtp.163.com,作为发送邮件的服务器ip,类似的邮箱服务器应该也可以. MailSenderInfo m ...
- MySQL中innodb引擎分析(初始化)
MySQL的存储引擎是以插件形式工作的,这应该是MySQL的一大特色了吧! 依据<深入理解MySQL>的内容,5.1版本号时存储引擎的插件化都还不是彻底,确切的说是刚加入的特性.为MySQ ...
- Eclipse用法和技巧二十:一个快速打印技巧
调试的时候经常用到打印语句,当需要添加的说明字符串和需要打印的数值混淆到一起的时候,需要先写字符串如,"the string here is",接着再输入变量的值.这样一来一去还是 ...
- How to install vim on linux
前几日了解到 vim 文本编辑器,据说很强大,使用起来效率很高,今天怀着很好奇的心理,学习了一下vim编辑器的下载安装方法,在此详细介绍一下安装vim编辑器的几种常用方法: 第一种方法就是在 Ubun ...
- 工作线程AfxBeginThread的使用
工作线程通常用来执行一些后台任务,如:数据计算.后台杀毒等等.因为不需要创建窗口和处理用户消息,编写比较容易,在程序中只要调用AfxBeginThread 函数就可以创建并启动一个工作线程了. Afx ...
- POJ - 1422 Air Raid 二分图最大匹配
题目大意:有n个点,m条单向线段.如今问要从几个点出发才干遍历到全部的点 解题思路:二分图最大匹配,仅仅要一条匹配,就表示两个点联通,两个点联通仅仅须要选取当中一个点就可以,所以有多少条匹配.就能够减 ...
- 微软vs2015先行,Visual Studio 2015正式版离线iso及在线下载(附key)附带百度云盘地址
win10正式版发布之前我们迎来了vs2015正式版,迫不及待要下载朋友可以看看 Visual Studio Community 2015简体中文版(社区版,针对个人免费): 在线安装exe:http ...
- PB+MS SQL+触发器必须指出
PB+MS SQL+触发器必须指出: 若触发器存在两笔以上的返回值,比方两条update 语句,被误判为数据有改变.存盘不成功. 提示: Row changed between retrieve an ...