一.为什么要使用泛型
1.比如我们又如下三个方法:
/// <summary>
/// 打印个int值
/// </summary>
/// <param name="parameter"></param>
public static void ShowInt(int parameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, parameter.GetType().Name, parameter);
}
/// <summary>
/// 打印个string值
/// </summary>
/// <param name="parameter"></param>
public static void ShowString(string parameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, parameter.GetType().Name, parameter);
}
/// <summary>
/// 打印个DateTime值
/// </summary>
/// <param name="parameter"></param>
public static void ShowDateTime(DateTime parameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod).Name, parameter.GetType().Name, parameter);
}
调用:
int iValue = 123;
string sValue = "456";
DateTime dtValue = DateTime.Now;
CommonMethod.ShowInt(iValue);
CommonMethod.ShowString(sValue);
CommonMethod.ShowDateTime(dtValue);
思考:我们可以看到这三个方法基本相同只是参数类型不同,那么我们怎么同一个方法来写呢?
可能大家首先考虑的是object。
那么我们先用object实现
/// <summary>
/// 打印个object值
/// </summary>
/// <param name="oParameter"></param>
public static void ShowObject(object oParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), oParameter.GetType().Name, oParameter);
}
//调用
object oValue = "678";
CommonMethod.ShowObject(iValue);
CommonMethod.ShowObject(sValue);
CommonMethod.ShowObject(dtValue);
CommonMethod.ShowObject(oValue);
1.但是我们都知道object是引用类型,存在堆内存中。值类型存在栈内存中。所以上面存在装箱和拆箱。首先值类型先要变成引用类型装箱过程,后面方法执行又要变成值类型拆箱过程。还是一个很消耗资源的过程。这就是性能消耗问题
2.同时存在类型安全问题。比如我再showObject写int a= Convert.ToInt32(oParameter);他在编译的时候不会报错,但是在执行的时候传入不能转成int类型的就会出错。这就是类型安全问题
/// <summary>
/// 打印个object值
/// </summary>
/// <param name="oParameter"></param>
public static void ShowObject(object oParameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), oParameter.GetType().Name, oParameter);
int a= Convert.ToInt32(oParameter);//添加
}
为了解决这两个问题同时又支持一个方法可以传不同的参数类型,所以就出现了泛型.
泛型的优势:比object的性能又快,同时不会出现类型安全问题。(因为在编译时有类型问题就会直接报错)
一、泛型原理:泛型在经过编译以后没有确定类型,它是在运行时CLR 中的及时编译器(jit),确定是某一个具体的类型;
二、泛型的设计
1.声明的时候有一个占位符----不确定他的类型
2.运行的时候确定类型---延迟声明;
泛型有:泛型方法,泛型类(比如List类),泛型委托,泛型接口等。
/// <summary>
/// 泛型方法:不同类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tPrarameter"></param>
public static void ShowGeneric<T>(T tPrarameter)
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tPrarameter.GetType().Name, tPrarameter);
}
//调用
int iValue = 123;
string sValue = "456";
DateTime dtValue = DateTime.Now;
CommonMethod.ShowGeneric<int>(iValue); //
CommonMethod.ShowGeneric<string>(sValue);
CommonMethod.ShowGeneric<DateTime>(dtValue);
CommonMethod.ShowGeneric(oValue);
泛型方法的特点:
1.调用的时候---指定类型
2.指定的类型必须和参数类型一致
3.在调用的时候,如果可以根据参数推导出类型,尖括号中的类型声明可以省略不写;
泛型是如何解决类型安全问题的呢?答案是通过泛型约束
比如我用这些基础类.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AspNetCore.Generic
{
public interface ISports
{
void Pingpang();
}
public interface IWork
{
void Work();
}
public class People
{
public People()
{
}
public int Id { get; set; }
public string Name { get; set; }
public void Hi()
{ }
}
public class Chinese : People, ISports, IWork
{
public void Tradition()
{
Console.WriteLine("仁义礼智信,温良恭俭让");
}
public void SayHi()
{
Console.WriteLine("吃了么?");
}
public void Pingpang()
{
Console.WriteLine("打乒乓球...");
}
public void Work()
{
throw new NotImplementedException();
}
}
public class Hubei : Chinese
{
public string Changjiang { get; set; }
public void Majiang()
{
Console.WriteLine("打麻将啦。。");
}
}
public class Japanese : ISports
{
public int Id { get; set; }
public string Name { get; set; }
public void Pingpang()
{
Console.WriteLine("打乒乓球...");
}
}
}
类型约束:
/// <summary>
/// 基类约束,限定必须是People类
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="oParameter"></param>
public static void Show<T>(T tParameter) where T:People
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tParameter.GetType().Name, tParameter);
Console.WriteLine($"People.Id={tParameter.Id}");
Console.WriteLine($"People.Id={tParameter.Name}");
}
/// <summary>
/// 接口约束:限定T 是ISports接口或者是ISports实现类;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowInterface<T>(T tParameter) where T : ISports
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tParameter.GetType().Name, tParameter);
//Console.WriteLine($"People.Id={tParameter.Id}");
//Console.WriteLine($"People.Id={tParameter.Name}");
tParameter.Pingpang();
}
/// <summary>
/// 引用类型约束 约束T 必须是引用类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowClass<T>(T tParameter) where T : class
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tParameter.GetType().Name, tParameter);
}
/// <summary>
///值类型约束: 约束T 必须是值类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowStruct<T>(T tParameter) where T : struct
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tParameter.GetType().Name, tParameter);
}
/// <summary>
///无参数构造函数约束: 约束T 必须有一个无参数构造函数 也就是可以直接New
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowNew<T>(T tParameter) where T : new()
{
Console.WriteLine("This is {0},parameter={1},type={2}",
typeof(CommonMethod), tParameter.GetType().Name, tParameter);
}
调用:
{
Console.WriteLine("***********************基类约束**************************");
GenericConstraint.Show(people);
GenericConstraint.Show(chinese);
GenericConstraint.Show(hubei);
//GenericConstraint.Show(japanese); //不是这个类型 编译器就直接报错;开发者就明确了错误;
}
{
//Console.WriteLine("***********************接口约束**************************");
GenericConstraint.ShowInterface(people);
//GenericConstraint.ShowInterface(chinese);
//GenericConstraint.ShowInterface(hubei);
//GenericConstraint.ShowInterface(japanese); //不是这个类型 编译器就直接报错;开发者就明确了错误;
}
{
Console.WriteLine("***********************引用类型约束**************************");
GenericConstraint.ShowClass(people);
GenericConstraint.ShowClass(chinese);
GenericConstraint.ShowClass(hubei);
GenericConstraint.ShowClass(japanese);
//GenericConstraint.ShowClass(iValue);
//GenericConstraint.ShowClass(sValue);
//GenericConstraint.ShowClass(dtValue);
}
{
//Console.WriteLine("***********************值类型约束**************************");
//GenericConstraint.ShowStruct(people);
//GenericConstraint.ShowStruct(chinese);
//GenericConstraint.ShowStruct(hubei);
//GenericConstraint.ShowStruct(japanese); //不是这个类型 编译器就直接报错;开发者就明确了错误;
//GenericConstraint.ShowStruct(iValue);
//GenericConstraint.ShowStruct(sValue);
//GenericConstraint.ShowStruct(dtValue);
}
{
Console.WriteLine("***********************无参数构造函数约束**************************");
//People people1 = new People();
//GenericConstraint.ShowNew(people);
GenericConstraint.ShowNew(chinese);
GenericConstraint.ShowNew(hubei);
GenericConstraint.ShowNew(japanese); //不是这个类型 编译器就直接报错;开发者就明确了错误;
GenericConstraint.ShowNew(iValue);
//GenericConstraint.ShowNew(sValue);
GenericConstraint.ShowNew(dtValue);
}