.net(一) 泛型generic使用和原理 封装泛型缓存

点击返回  .net 初级高级 武林秘籍内功

大纲:

1.泛型的由来: CLR+JIT  延迟申明

2.泛型与object的对比、代码举例

3.泛型类、泛型方法、泛型接口、泛型委托

4.泛型约束

5.泛型的协变逆变

 

1.泛型的由来: CLR+JIT  延迟申明

泛型基本概念:.NET 泛型是一个很强大的新特性,它为每一种对象生成一份单独的代码(也就是所谓的“实例化”),这一份量身顶做的代码具有很高的效率,是强类型的,不需要运行期多态的支持和负担,有了泛型,就不再需要Object类来参与实现一些通用类或方法了.

泛型的作用: 在CLR(common language runtime)1.0中,当要创建一个灵活的类或方法,但该类或方法在编译期问不知道使用什么类,就必须以System.Object类为基础进行处理,而Object类在编译期间没有类型安全性,又必须进行强制类型转换.另外,给值类型使用Object类会有性能损失,这给程序开发带来诸多不便.故在CLR 2.0(.NET 3.5基于CLR 2.0)中,提供了泛型.

通过使用泛型类型,可以根据需要,用特定的类型替换泛型类型,同时保证了类型安全性:如果某个类型不支持泛型类,编译器就会报错,以阻止程度发生运行期错误.正确使用泛型将大大提高代码的灵活性,结合一个优秀的设计模式,可以显著缩短开发时间.
总而言之:泛型,其实就是 CLR+JIT的支持,使用泛型,可以重用代码,由CLR+JIT延迟等编译和执行的时候生成一个个具体的类或方法等等 的副本。比如:public class A<T>类,这样,我new的时候,var aStr= new A<string>();var aInt=new A<int>();这样,其实在编译的时候,会生成 A_001(string) 类和A_002 (int)类。 
 
 
 2.泛型与object的对比、代码举例
以上要是看的不是很懂的,例子来了。
比如我们需要打印出,传入参数的类型名称,那么使用常规代码方式,有常用2种方式去实现:
第一种,调用对应的showInt(),showString(),showTime().........方法,如下:
常规代码使用(令狐冲练的武功就是这样的):
/// <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="oParameter"></param>
public static void ShowDateTime(DateTime dtParameter)
{
    Console.WriteLine("This is {0},parameter={1},type={2}",
        typeof(CommonMethod).Name, dtParameter.GetType().Name, dtParameter);
}
//如果做数据库查询,每一个实体对应的表,那岂不是每一个实体都要写一个方法吗?
看看调用:

int iValue = 123;
string sValue = "456";
DateTime dtValue = DateTime.Now;
object oValue = "789";

ShowInt(iValue);
ShowString(sValue);
ShowDateTime(dtValue);
常规代码使用
第二种,使用showObject(object oParameter);
使用object(岳不群自宫):
/// <summary> 
///为什么用object 作为参数类型,调用的时候,可以把任何类型都传进来
///
///C#: 任何父类出现的地方  都可以用子类代替;
///Object类型是一切类型的父类
///
///Object 出现的都可以让任何类型传进来
/// 
/// 但是:有2个问题
///        性能问题:会出现装箱和拆箱;
///        类型安全问题。 
/// </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);
}

看看调用:
ShowInt(iValue);
ShowString(sValue);
ShowDateTime(dtValue);
使用object
 泛型类使用(小林子的葵花宝典):
/// <summary>
/// 泛型方法:需要在方法名的后面带一个<>,需要定义T, T是什么呢? 不知道, 
/// T:类型参数,只是一个占位符,类型在声明其实不确定,在调用的时候,确定类型。
///  
/// 延迟声明,推迟一切可以推迟的,事情能晚点做就晚点做。 
/// 在使用的时候,需要指定明确的类型
/// 泛型方法性能和普通方法差不多,可以用一个方法满足多个类型的需求 
/// 集成了前面2种的各自的长处。既可以安全调用,性能又好,并且可以用一个方法代替N个方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void Show<T>(T tParameter)
{
    Console.WriteLine("This is {0},parameter={1},type={2}",
        typeof(CommonMethod), tParameter.GetType().Name, tParameter);
}

看看调用:

Show(iValue); //如果类型参数,可以通过参数类型推导出来,那么就可以省略
/* Show<int>(sValue);*/// 因为类型错了 
Show(sValue);
Show<DateTime>(dtValue);
Show<object>(oValue);
使用泛型

 3.泛型类、泛型方法、泛型接口、泛型委托

泛型方法 一个方法满足多个类型的需求
泛型类 就是一个类 满足多个类型的需求
泛型接口 就是一个接口 满足多个多个类型的需求
泛型委托 就是一个委托 满足多个多个类型的需求

 

a.泛型类:

//泛型类的定义在常规的类后面加<T>,T为占位符,可以任何字符代替。
//eg:  public class Student<T>{}
//亦可以多个类型。占位符不重复,用逗号隔开
//eg:  public class People<T,A,B,C>{}

//例子a:
public class ClassA<T>
{
    /// <summary>
    /// 获取T的类型全名称
    /// </summary>
    /// <returns></returns>
    public string GetTTypeName()
    {
        return typeof(T).FullName;
    }
}
//使用
//使用泛型来打印实例类型
{
    ClassA<int> aInt = new ClassA<int>();
    Console.WriteLine(aInt.GetTTypeName());//System.Int32

    ClassA<string> aStr = new ClassA<string>();
    Console.WriteLine(aStr.GetTTypeName());//System.String

    Console.ReadLine();
}

//例子b:
public class ClassB<T,A> 
    where T:struct  //约束T是个struct
    where A:class,new () //约束A是个引用类型,无参数构造函数约束
{
    /// <summary>
    /// 获取T的类型全名称
    /// </summary>
    /// <returns></returns>
    public string GetTTypeName()
    {
        return typeof(T).FullName;
    }
}
泛型类

 

b.泛型方法:

例子在上面的2.“使用泛型”那有。

 

c.泛型接口:

//我们有4个类(人类、中国人、广东人、日本人),
//中国人继承人类,广东人继承中国人。日本人没继承人类。
//有2个接口(IWork,ISports)

public interface ISports
{
    void Pingpang();
}

public interface IWork
{
    void Work();
}

/// <summary>
/// 人类
/// 基本属性有:ID,名称,会说Hi
/// </summary>
public class People
{
    public int Id { get; set; }
    public string Name { get; set; }
    public void Hi()
    { }
}

/// <summary>
/// 中国人:继承了人类(拥有人类的基本属性)
/// 也有自己的说Hi方式,有额外的属性,还实现了运动,工作
/// </summary>
public class Chinese : People, ISports, IWork
{
    public void Tradition()
    {
        Console.WriteLine("仁义礼智信,温良恭俭让");
    }
    public void SayHi()
    {
        Console.WriteLine("吃了么?");
    }
    public void Pingpang()
    {
        Console.WriteLine("打乒乓球...");
    }
    public void Work()
    {
        Console.WriteLine("工作中...");
    }
}

/// <summary>
/// 广东人:继承了中国人(拥有中国人的基本属性)
/// 额外还会吃。
/// </summary>
public class GuangDong : Chinese {
    public void Eat()
    {
        Console.WriteLine("正在吃福建人...");
    }
}

/// <summary>
/// 日本人:只实现了运动
/// </summary>
public class Japanese : ISports
{
    public int Id { get; set; }
    public string Name { get; set; }

    public void Pingpang()
    {
        Console.WriteLine("雅美蝶,打乒乓球...");
    }
}


//如下调用
People people = new People()
{
    Id = 1,
    Name = "令狐冲"
};
Chinese chinese = new Chinese()
{
    Id = 2,
    Name = "岳不群"
};
GuangDong guangDong = new GuangDong()
{
    Id = 3,
    Name = "小林子"
};
Japanese japanese = new Japanese()
{
    Id = 4,
    Name = "冲田杏梨"
};

//现在有这4个对象
//我想要他们,统统运动起来,如下:
//常规:
// people 没有运动的方法
chinese.Pingpang();
guangDong.Pingpang();
japanese.Pingpang();

//如果,我想他们统统运动起来,使用把对象传入进去的方法,
//那么又回到上面我说,替这3个类加3个方法
/*eg:
 * public static void ChineseShowSports(Chinese chinese){ chinese.Pingpang(); }
 * public static void GuangDongShowSports(GuangDong guangDong){guangDong.Pingpang(); }
 * public static void JapaneseShowSports(Japanese japanese){japanese.Pingpang(); }
 */
 //调用如下
ChineseShowSports(chinese);
GuangDongShowSports(guangDong);
JapaneseShowSports(japanese);


//这样也是可以的,那么下面的泛型就可以把他们泛型成一个方法
/*eg:
 * public static void ShowSports<T>(T t) where T: People,ISports
 * {
 *     t.Pingpang();
 * }
 */
//调用如下
ShowSports(chinese);
ShowSports(guangDong);
ShowSports(japanese);
View Code

    

 

从这俩张图可见,where T 起到了约束,所以可以使用里面的方法和属性。

 

4.泛型约束

在上面的代码中,可以看到一些泛型约束的使用了。

泛型约束 是 在泛型类、方法、等对其调用的约束,起到保护作用和使用(履行义务+享受权利),使用方法是  后面跟 where T : Class,new()等。多重约束使用逗号隔开。

多泛型如T,G,F,使用多个where。如:

public static void ShowSports<T,G,F>(T t)

where T :People,ISports

where G:ISports

where F:Class

{
  //这里是业务,可以使用 T,G,F
}
View Code

说明

where T:People// 约束T是People类型

where T:ISports// 约束T是实现ISports类型

where T :Class// 约束T是引用类型
where T :new()// 无参数构造的函数约束

where T :struct// 约束T是结构类型

举个例子

我要这3个对象运动一下,要求是个人才能运动

public static void ShowSportsByPeople<T>(T t) where T :People, ISports
{
    t.Pingpang();
}

//调用
ShowSportsByPeople(chinese);//打乒乓球...
ShowSportsByPeople(guangDong);//打乒乓球...
ShowSportsByPeople(japanese);//这个会报错,老师亚麻跌不出来
//说明泛型约束,保证了调用安全。
View Code

 

5.泛型的协变逆变

选修:in out

哈哈,不说了

 

 

 

 

 

点击返回  .net 初级高级 武林秘籍内功

posted @ 2020-01-08 12:18  CaptainBruke  阅读(512)  评论(0编辑  收藏  举报