一、泛型引入

  需求:传入一个类型(整型/日期/字符串或其他),打印出它的类型和内容。  

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#进阶学习】泛型的更多相关文章

  1. Mybatis基础进阶学习2

    Mybatis基础进阶学习2 1.测试基本结构 2.三个POJO package com.pojo; import java.io.Serializable; import java.util.Dat ...

  2. 爱了!阿里大神最佳总结“Flutter进阶学习笔记”,理论与实战

    前言 "小步快跑.快速迭代"的开发大环境下,"一套代码.多端运行"是很多开发团队的梦想,美团也一样.他们做了很多跨平台开发框架的尝试:React Native. ...

  3. PHP程序员进阶学习书籍参考指南

    PHP程序员进阶学习书籍参考指南 @heiyeluren lastmodify: 2016/2/18     [初阶](基础知识及入门)   01. <PHP与MySQL程序设计(第4版)> ...

  4. Matlab 进阶学习记录

    最近在看 Faster RCNN的Matlab code,发现很多matlab技巧,在此记录: 1. conf_proposal  =  proposal_config('image_means', ...

  5. 在学习泛型时遇到的困惑经常与func<T,U>混淆

    在学习泛型时遇到的困惑经常与func<T,U>混淆,总认为最后一个值是返回类型.现在区分一下,原来问题出在泛型委托上. C#委托的介绍(delegate.Action.Func.predi ...

  6. zuul进阶学习(二)

    1. zuul进阶学习(二) 1.1. zuul对接apollo 1.1.1. Netflix Archaius 1.1.2. 定期拉 1.2. zuul生产管理实践 1.2.1. zuul网关参考部 ...

  7. ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - ROSMapModify - ROS地图修改

    ROS进阶学习笔记(11)- Turtlebot Navigation and SLAM - 2 - MapModify地图修改 We can use gmapping model to genera ...

  8. Spring.NET依赖注入框架学习-- 泛型对象的创建和使用

    Spring.NET依赖注入框架学习-- 泛型对象的创建和使用 泛型对象的创建方法和普通对象是一样的. 通过构造器创建泛型对象 下面是一个泛型类的代码: namespace GenericsPlay ...

  9. Struts2进阶学习4

    Struts2进阶学习4 自定义拦截器的使用 核心配置文件 <?xml version="1.0" encoding="UTF-8"?> <! ...

  10. Struts2进阶学习3

    Struts2进阶学习3 OGNL表达式与Struts2的整合 核心配置文件与页面 <?xml version="1.0" encoding="UTF-8" ...

随机推荐

  1. 【Mysql】了解Mysql中的启动参数和系统变量

    一.启动参数 在程序启动时指定的设置项也称之为启动选项(startup options),这些选项控制着程序启动后的行为. 1)在命令行上使用选项 启动服务器程序的命令行后边指定启动选项的通用格式就是 ...

  2. python 类 专有方法

    __init__ : 构造函数,在生成对象时调用 __del__ : 析构函数,释放对象时使用 __repr__ : 打印,转换 __setitem__ : 按照索引赋值 __getitem__: 按 ...

  3. [基础]Deep Learning的基础概念

    目录 DNN CNN DNN VS CNN Example 卷积的好处why convolution? DCNN 卷积核移动的步长 stride 激活函数 active function 通道 cha ...

  4. Nginx 初步认识

    序言 Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的.从2004年发布至今,凭借开源的力量,已经接近成熟与完善. Nginx功能丰富,可作为HTTP服务器,也 ...

  5. Codeforces Round #590 (Div. 3) F

    传送门 题意: 给出一个只含前\(20\)个字符的字符串,现在可以选择一段区间进行翻转,问区间中字符各不相同时,最长长度为多少. 思路: 首先,容易将题意转换为选择两个字符各不相同的区间,然后长度相加 ...

  6. 201871010124--王生涛--《面向对象程序设计(java)》第十二周学习总结

    博文正文开头格式: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nw ...

  7. CentOS 8 网卡命令

    nmcli n 查看nmcli状态 nmcli n on 启动nmcli nmcli c  up eth0 启动网卡eth0 nmcli c down eth0 关闭网卡eth0 nmcli d c ...

  8. explain慢SQL分析解释

    使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是 如何处理你的SQL语句的.分析你的查询语句或是表结构的性能瓶颈. 使用方式:Explain+SQL语句 执行计划包含的信 ...

  9. pom.xml文件说明(八)

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  10. 微信小程序 - Request | 路由跳转 | 本地存储

    Request 官方文档 wx.request相当于发送ajax请求 参数 属性 类型 默认值 必填 说明 url string   是 开发者服务器接口地址 data string/object/A ...