【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" ...
随机推荐
- Java八大排序之希尔(Shell)排序
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该 ...
- 4-剑指offer: 把数组排成最小的数
题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 代码: cl ...
- Netty之ChannelHandler(三)
ChannelHandler是netty中的核心处理部分,我们使用netty的绝大部分代码都写在这部分,所以了解它的一些机制和特性是很有必要的. 一.Channel Channel接口抽象了底层soc ...
- Identity入门2:AuthenticationManager【转】
在 上篇文章 中讲了关于 Identity 需要了解的单词以及相对应的几个知识点,并且知道了Identity处在整个登入流程中的位置,本篇主要是在 .NET 整个认证系统中比较重要的一个环节,就是 认 ...
- django -- admin里的配置
前戏 Django给我们提供了一个后台管理系统,方便我们进行数据表的管理 创建超级用户 python manage.py createsuperuser 配置 默认我们登录到后台不显示任何一张表,如果 ...
- js中VO解析
执行环境(环境) 执行环境的用处 执行环境定义了变量或函数有权访问的其他数据,每一个执行环境都存在一个关联的变量对象(VO),代码无法访问,内部解析器会使用它,如果环境为函数,则将函数的AO作为VO, ...
- Linux性能优化实战学习笔记:第二十四讲
一.磁盘 1.机械磁盘 2.固态磁盘 3.相同磁盘随机I/O比连续I/O慢很多 4.最小单位 5.接口 6.RAID陈列卡 7.网路存储 二.通用块层 1.概念 2.第一功能 3.第二功能 4.I/O ...
- [LeetCode] 623. Add One Row to Tree 二叉树中增加一行
Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...
- 热情组——项目冲刺 Day7
项目相关 作业相关 具体描述 班级 班级链接 作业要求 链接地址 团队名称 热情组 作业目标 实现软件制作,以及在福大的传播 Github链接 链接地址 SCRUM部分: 成员昵称 昨日目标 开始时间 ...
- div 中 id 和 class使用详解【转】
原文地址:https://blog.csdn.net/zxw136511485/article/details/71191053 在div 标签中,我们比较常见的属性是id 和class,那么这两个属 ...