一、泛型引入

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

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. 简单使用:SpringBoot使用freemarker

    使用步骤: a : 添加依赖 b: 创建模板文件 保存位置resources/templates 目录下 文件后缀名.ftl c 编写controller 把结果传递给模板 在resources.te ...

  2. liteos信号量(八)

    1. 概述 1.1 基本概念 信号量(Semaphore)是一种实现任务间通信的机制,实现任务之间同步或临界资源的互斥访问.常用于协助一组相互竞争的任务来访问临界资源. 在多任务系统中,各任务之间需要 ...

  3. 模板渲染 templates

    目录 一.模板含义 二.模板的组成 三.逻辑控制代码 变量 标签 自定义过滤器 模板继承 一.模板含义 模板虽然是HTML文件,但是Django不是直接把HTML文件返回给用户,而是经过了 模板语言的 ...

  4. React 受控组件和非受控组件

    需求用户名自动获取 onChange用户状态发生改变 就获取值 就是时时获取值 使用onChange 点击按钮 获取密码 只要绑定了点击事件 就可以获取值 通过 let usercont=event. ...

  5. Springboot将数据存储到数据库当中

    1.从前端获取数据,同时存储到use当中 public String login(HttpServletRequest request) { User user = new User(); user. ...

  6. pikachu的xss及csrf

    一.XSS 可解析的js 未经过滤 XSS见框就插     script 大小写  中间插入 <img src="" onerror="alert(11111)&q ...

  7. opencv鼠标事件

    #include <opencv2\opencv.hpp> using namespace cv; struct mouse_para { cv::Mat org; cv::Mat img ...

  8. centos虚拟机 与主机同步时间

    同步系统时间: yum install ntp ntpdate cn.pool.ntp.org ntpdate 0.centos.pool.ntp.org rm /etc/localtime ln - ...

  9. 树莓派安装opencv3及其扩展库

    https://www.cnblogs.com/Pyrokine/p/8921285.html 目标编译针对python的opencv以及扩展库 环境树莓派4和3B+都可以python3.7.3 py ...

  10. selenium--cookie操作

    前戏 在做自动化的时候,遇到难处理的验证码,我们可以手动登录,然后获取登录到的cookie,添加到浏览器中,就可以实现登录 实战 from selenium import webdriver driv ...