【C#进阶学习】泛型
一、泛型引入
需求:传入一个类型(整型/日期/字符串或其他),打印出它的类型和内容。
1.初级版
public class CommonMethod
{
/// <summary>
/// 打印int值
/// </summary>
/// <param name="iParameter"></param>
public static void ShowInt(int iParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
} /// <summary>
/// 打印string值
/// </summary>
/// <param name="sParameter"></param>
public static void ShowString(string sParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
} /// <summary>
/// 打印DateTime值
/// </summary>
/// <param name="dParameter"></param>
public static void ShowDateTime(DateTime dParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, dParameter.GetType().Name, dParameter);
}
}
typeof和gettype的区别
调用
static void Main(string[] args)
{
DateTime dt = DateTime.Now;
int i = ;
string test = "test";
object o = new object();
CommonMethod.ShowDateTime(dt);
CommonMethod.ShowInt(i);
CommonMethod.ShowString(test);
}
2.升级版
/// <summary>
/// 打印object值
/// 1.object是一切类型的基础
/// 2.通过集成,子类拥有父类的一切属性和行为
/// </summary>
/// <param name="o"></param>
public static void ShowObject(object oParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, oParameter.GetType().Name, oParameter);
}
调用
DateTime dt = DateTime.Now;
int i = ;
string test = "test";
object o = new object();
CommonMethod.ShowObject(dt);
CommonMethod.ShowObject(i);
CommonMethod.ShowObject(test);
CommonMethod.ShowObject(o);
缺点:如果传递的是值类型,会装箱拆箱
二、泛型来喽
定义泛型
public class GenericMethod
{
/// <summary>
/// 方法名字后面带上尖括号 类型参数
/// T可以换成其他任何未定义的名称,但是不要用关键字、类名等等
/// 来自 .net framework2.0 CLR升级的
/// 解决相同内容/操作,对于不同参数的问题
///
/// 延迟声明,声明方法的时候没有指定参数类型,而是等到调用的时候指定
/// 延迟思想:推迟一切可以推迟的
///
/// 编译的时候 类型参数编译为占位符 `(1旁边英文输入状态)
/// 程序运行的时候,jit即时编译替换为真实类型
///
///
/// </summary>
/// <param name="o"></param>
public static void Show<T>(T tParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
}
}
调用
GenericMethod.Show<DateTime>(dt);
GenericMethod.Show(dt);//不指定类型参数,编译器自动推算(编译器的语法糖)
GenericMethod.Show<int>(i);
GenericMethod.Show<string>(test);
GenericMethod.Show<object>(o);
三、消耗时间对比
using System;
using System.Diagnostics; namespace MyGeneric
{
public class Monitor
{
public static void Show()
{
Console.WriteLine("******************Monitor****************");
int iValue = ;
long commonSecond = ;
long objectSecond = ;
long genericSecond = ; {
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = ; i < ; i++)
{
ShowInt(iValue);
}
watch.Stop();
commonSecond = watch.ElapsedMilliseconds;
} {
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i=;i<;i++)
{
ShowObject(iValue);
}
watch.Stop();
objectSecond = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = ; i < ; i++)
{
Show(iValue);
}
watch.Stop();
genericSecond = watch.ElapsedMilliseconds;
}
Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}",
commonSecond, objectSecond, genericSecond);
Console.Read();
} public static void ShowInt(int iParameter)
{
//do nothing
} public static void ShowObject(object oParameter)
{
//do nothing
} public static void Show<T>(T tParameter)
{
//do nothing
}
}
}
调试启动的时间如下,可以看出泛型执行的时间是最短的。
如果更换顺序,将执行泛型的方法放到第一位的话,会出现泛型时间和普通时间一样,甚至还会比它耗费时间长的情况。

ctrl+F5启动时间对比如下(这一块不懂,为什么普通方法要比泛型的时间快呢)

四、泛型类
using System; namespace MyGeneric
{
//泛型类
public class GenericClass<W,Jasmine,Apple>//参数类型可以随便指定,意思就是相当于在这个类中定义了一个w的类型
{
public void Show(W w) { }
public Jasmine Get()
{
return default(Jasmine);
}
}
/// <summary>
/// 泛型接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IStudy<T>
{
T Study(T t);
}
public delegate Everything GetHandler<Everything>();//泛型委托 /// <summary>
/// 普通类
/// </summary>
public class Child
//: GenericClass<string,int,string> //指定类型参数后即可继承
//:GenericClass<W, Jasmine, Apple> 这种写法是错误的,普通类不能直接继承泛型类
//:IStudy<T> 普通类不能直接实现泛型接口
: IStudy<string>
{
public string Study(string t)
{
throw new NotImplementedException();
}
} public class GenericChild<W,Jasmine, Apple>
//: GenericClass<W,Jasmine,Apple> //泛型类可以直接继承泛型类
//public class GenericChild<W, Jasmine>//等于声明了两个局部类型 W和Jasmin
//: GenericClass<W, Jasmine, string>
:IStudy<W> //泛型类不能直接实现泛型接口
{
public W Study(W t)
{
throw new NotImplementedException();
}
} }
五、泛型约束
1.所需模型
using System; namespace MyGeneric
{
public class Model
{
public class People
{
public int Id { get; set; }
public string Name { get; set; }
public void Hi()
{
}
} public interface ISports
{
void PingPang();
} public interface IWork
{
void Work();
} public class Chinese : People,ISports,IWork
{
public void Tradition()
{
Console.WriteLine("谦虚");
}
public void SayHi()
{
} public void PingPang()
{
throw new NotImplementedException();
} public void Work()
{
throw new NotImplementedException();
}
} public class Sichuan : Chinese
{
public string Panda { get; set; }
public void Huoguo()
{
Console.WriteLine("吃火锅啦");
}
}
} }
2.泛型约束(基类约束)
using System;
using static MyGeneric.Model; namespace MyGeneric
{
public class Constraint
{
/// <summary>
/// 有约束才有自由,有权利就得有义务
///
/// 1.基类约束,就可以访问基类的方法和属性(基类/子类)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void Show<T>(T tParameter) where T : People //基类约束
{
Console.WriteLine("This is {0},parameter={2},type={1}",
typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter); Console.WriteLine(tParameter.Id);
Console.WriteLine(tParameter.Name);
tParameter.Hi();
}
}
}
调用
People people = new People()
{
Id = ,
Name = "张三"
};
Chinese chinese = new Chinese()
{
Id = ,
Name = "李四"
};
Sichuan sichuan = new Sichuan()
{
Id = ,
Name = "小红"
}; Constraint.Show(people);
Constraint.Show(chinese);
Constraint.Show(sichuan);
3.泛型约束(接口约束)
public static void ShowSports<T>(T tParameter) where T : ISports //基类约束
{
Console.WriteLine("This is {0},parameter={2},type={1}",
typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter); tParameter.PingPang();
}
调用和上面的相同,实现了该接口的类,可直接当做参数传入。
4.其他泛型约束写法
public static T Get<T>()
//where T:class //引用类型约束
//where T:struct//值类型约束
where T:new() //无参数构造函数约束
{
T t = new T();
return default(T);
}
六、协变
1.相关模型(Sparrow是Bird的子类)
public class Bird
{
} public class Sparrow : Bird
{
}
2.
Bird bird1 = new Bird();
//左边父类,右边子类
Bird bird2 = new Sparrow();
Sparrow sparrow1 = new Sparrow();
List<Bird> birdList1 = new List<Bird>();
//List<Bird> bird3 = new List<Sparrow>(); //不是父子关系,没有继承关系 List<Bird> birdlist2 = new List<Sparrow>().Select(s => (Bird)s).ToList();
3.查看IEnumerable定义,可以看到有一个关键字out

4.下面可实现左边是父类,右边是子类
//协变
IEnumerable<Bird> birdList4 = new List<Bird>();
IEnumerable<Bird> birdList5 = new List<Sparrow>();//协变
5.具体应用
/// <summary>
/// out协变 只能是返回值
/// 协变逆变只存在于接口或者委托
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ICustomerListOut<out T>
{
T Get();
//void Show(T t); // 此处错误,T不能作为传入参数
} /// <summary>
/// 类没有协变逆变
/// </summary>
/// <typeparam name="T"></typeparam>
public class CustomerListOut<T> : ICustomerListOut<T>
{
public T Get()
{
return default(T);
}
}
调用
ICustomerListOut<Bird> customerList = new CustomerListOut<Bird>();
ICustomerListOut<Bird> customerList1 = new CustomerListOut<Sparrow>(); //协变
七、逆变
1.定义
public interface ICustomerListIn<in T>
{
//T Get(); void Show(T t);
} /// <summary>
/// 逆变 只能作为参数传入
/// </summary>
/// <typeparam name="T"></typeparam>
public class CustomerListIn<T> : ICustomerListIn<T>
{
//T Get(); //不能作为返回值 public void Show(T t)
{
}
}
2.调用
//逆变
ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
ICustomerListIn<Sparrow> customerList3 = new CustomerListIn<Bird>(); //左边是子类的时候,右边可以是父类 ICustomerListIn<Bird> birdList6 = new CustomerListIn<Bird>();
birdList6.Show(new Sparrow());
birdList6.Show(new Bird());
八、协变逆变混合应用
1.定义
public interface IMyList<in inT, out outT>
{
void Show(inT t);
outT Get();
outT Do(inT t); //out只能是返回值 in只能是参数
} public class MyList<T1, T2> : IMyList<T1, T2>
{ public void Show(T1 t)
{
Console.WriteLine(t.GetType().Name);
}
public T2 Get()
{
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
public T2 Do(T1 t)
{
Console.WriteLine(t.GetType().Name);
Console.WriteLine(typeof(T2).Name);
return default(T2);
}
}
2.调用
IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>();
IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>(); //协变
IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>(); //逆变
IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>(); //逆变
九、泛型缓存
不太懂,有时间再好好研究下(捂脸......)
【C#进阶学习】泛型的更多相关文章
- Mybatis基础进阶学习2
		
Mybatis基础进阶学习2 1.测试基本结构 2.三个POJO package com.pojo; import java.io.Serializable; import java.util.Dat ...
 - 爱了!阿里大神最佳总结“Flutter进阶学习笔记”,理论与实战
		
前言 "小步快跑.快速迭代"的开发大环境下,"一套代码.多端运行"是很多开发团队的梦想,美团也一样.他们做了很多跨平台开发框架的尝试:React Native. ...
 - PHP程序员进阶学习书籍参考指南
		
PHP程序员进阶学习书籍参考指南 @heiyeluren lastmodify: 2016/2/18 [初阶](基础知识及入门) 01. <PHP与MySQL程序设计(第4版)> ...
 - Matlab 进阶学习记录
		
最近在看 Faster RCNN的Matlab code,发现很多matlab技巧,在此记录: 1. conf_proposal = proposal_config('image_means', ...
 - 在学习泛型时遇到的困惑经常与func<T,U>混淆
		
在学习泛型时遇到的困惑经常与func<T,U>混淆,总认为最后一个值是返回类型.现在区分一下,原来问题出在泛型委托上. C#委托的介绍(delegate.Action.Func.predi ...
 - zuul进阶学习(二)
		
1. zuul进阶学习(二) 1.1. zuul对接apollo 1.1.1. Netflix Archaius 1.1.2. 定期拉 1.2. zuul生产管理实践 1.2.1. zuul网关参考部 ...
 - ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改
		
ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...
 - Spring.NET依赖注入框架学习-- 泛型对象的创建和使用
		
Spring.NET依赖注入框架学习-- 泛型对象的创建和使用 泛型对象的创建方法和普通对象是一样的. 通过构造器创建泛型对象 下面是一个泛型类的代码: namespace GenericsPlay ...
 - Struts2进阶学习4
		
Struts2进阶学习4 自定义拦截器的使用 核心配置文件 <?xml version="1.0" encoding="UTF-8"?> <! ...
 - Struts2进阶学习3
		
Struts2进阶学习3 OGNL表达式与Struts2的整合 核心配置文件与页面 <?xml version="1.0" encoding="UTF-8" ...
 
随机推荐
- Nginx01(Nginx简介)
			
一:序言 Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的.从2004年发布至今,凭借开源的力量,已经接近成熟与完善. 二:Nginx常用功能 1.Http代理 ...
 - BeyondCompare4破解方法
			
因为工作需要,经常会用到BeyondCompare4这个软件,但是从官方下载的BeyondCompare4只有一个月的试用期,点击输入密钥又一直打开购买软件的页面,所以就一开始就用了最笨的方法,软件的 ...
 - Django框架(十六)-- 中间件、CSRF跨站请求伪造
			
一.什么是中间件 中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出 二.中间件的作用 如果你想修改请求,例如被传送到view ...
 - 【分布式搜索引擎】Elasticsearch之如何安装Elasticsearch
			
在Macos上安装 一.下载安装过程 最新版本下载地址: https://www.elastic.co/cn/downloads/elasticsearch 历史版本下载地址: https://www ...
 - 关于宝塔一个站点绑定多个域名宝塔ssl证书的问题
			
目前“宝塔SSL”自动申请绑定一个证书,即根域名和www域名,如果还需要绑定手机端m则需要绑定多个域名如果多域名绑定一个网站数据,需要新建多个站点指向同一文件目录. 用相同的方法,在不新建站点的前提下 ...
 - Rust中的闭包
			
这个功能有点高级, 暂时理解不完全, 先把代码练正确吧. use std::thread; use std::time::Duration; struct Cacher<T> where ...
 - 跟着ALEX 学python day5  模块
			
文档内容学习于 http://www.cnblogs.com/xiaozhiqi/ 模块 1.模块:用来从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能),本质就是.py结尾的pyt ...
 - Java虚拟机所管理的内存,包含的运行时数据区域?
			
运行时数据区域 线程私有(随用户线程的启动和结束而建立和销毁)或所有线程共享(随虚拟机进程的启动而存在) 抛出的异常 备注 程序计数器(Program Counter Register) 线程私有 唯 ...
 - python27期day13:闭包、装饰器初始、标准版装饰器、作业题
			
1.闭包: 保护数据安全.保护数据干净性. 2.闭包的定义:在嵌套函数内.使用非全局变量(且不使用本层变量) 将嵌套函数返回 闭包的目的:要接受被装饰的函数和被装饰函数需要的参数3.闭包举例子: de ...
 - 通过Socket实现TCP编程(十二)
			
原文链接:https://www.cnblogs.com/hysum/p/7531529.html Socket通信 : TCP协议是面向对象连接.可靠的.有序的,以字节流的方式发送数据. 基于TCP ...