.NET/C# 高级开发(一) 泛型
泛型入门:泛型方法,泛型类,泛型接口,泛型委托
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 泛型
{
class Program
{
static void Main(string[] args)
{
}
//泛型方法:参数作为泛型的方法
//服务于不同类型的共同需求的方法
public void 泛型方法_a<T>(T t)
{
}
//泛型方法:参数作为泛型的方法
//多泛型参数的方法,不可以用关键字
//不建议使用类名,变量名,方法名
public void 泛型方法_b<T,B,C>(T t)
{
}
//泛型方法:返回值作为泛型的方法
//object可以强转成泛型
public T 泛型方法_c<T>(object t)
{
return (T)t;
}
//泛型方法:返回值作为泛型的方法
//T t = default(T);//空的泛型变量,不可以用null
public T 泛型方法_d<T>()
{
T t = default(T);
return t;
}
}
//泛型类:将服务于不同类型的共同需求集合起来
public class 泛型类<T>
{
}
//泛型接口:服务于不同类型的共同需求的接口
public interface 泛型接口<T>
{
}
//泛型委托:服务于不同类型的共同需求的委托
public delegate void 泛型委托<T>();
}
泛型使用:延迟声明
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 泛型
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("************************声明不同类型变量方便演示**************************");
int iValue = 123;
string sValue = "456";
DateTime dValue = DateTime.Now;
object oValue = "789";
Console.WriteLine("************************ShowObject**************************");
//利用Object的基类特性传入参数,
//会产生两个问题:
//1.装箱拆箱,性能损耗
// 传入一个INT值(栈)
// (装箱) object是在堆里面的引用类型,如果把INT传递进来,会把值从栈里面Copy到堆里面
// (拆箱) 使用的时候需要用到对象值,又会从堆把值Copy到栈
//2.类型安全
// 传入的对象没有限制
// 如果传入的类型超出它的使用类型就会出问题
ShowObject(iValue);
ShowObject(sValue);
ShowObject(dValue);
ShowObject(oValue);
Console.WriteLine("************************ShowT**************************");
//泛型方法使用时要指明参数类型,
//编译器根据传入的参数类型自动推算泛型类型,这被我们成为语法糖,语法糖是编译器提供的便捷功能的代称
//如果指明的类型参数和传入的参数类型不符,编译不会通过
//编译阶段用占位符代替,是在运行阶段才确定的类型
//这类做法使用了延迟声明的设计思想,推迟一切可以推迟的
ShowT<int>(iValue);
ShowT(sValue);
ShowT(dValue);
ShowT(oValue);
Console.ReadKey();
}
static void ShowObject(object oParameter)//普通方法
{
Console.WriteLine($"传入的参数类型{oParameter.GetType().FullName},类型的值={tParameter}");
}
/// <summary>
/// 泛型方法:方法名称后面加上尖括号,里面是一个可以代指任何类型的代号
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
static void ShowT<T>(T tParameter)
{
Console.WriteLine($"传入的参数类型={tParameter.GetType().FullName},类型的值={tParameter}");
}
}
}
泛型扩展:泛型约束
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 泛型
{
class Program
{
static void Main(string[] args)
{
people peo = new people()
{
Id = 123,
Name = "人",
};
Chinese chi = new Chinese()
{
Id = 234,
Name = "中国人",
};
Hubei hub = new Hubei()
{
Id = 345,
Name = "湖北人",
};
Japanese Jap = new Japanese()
{
Id = 456,
Name = "日本人",
};
Show(peo);
Show(chi);
Show(hub);
Show(Jap);
Console.ReadKey();
}
public static void Show<T>(T t)
//where T : new //无参数构造函数,没有带参数构造函数
//where T : struct //值类型约束,当返回类型为泛型时可以用关键字default(T);会根据T的类型获得一个默认的值
//where T : class //引用类型约束
//where T : ISports //接口约束
//where T : people //基类约束
where T : people, ISports0, ISports1, new() //可以被一个基类/父类,多个接口同时约束,
//约束可以叠加但是有些不可以一起使用,因为没有意义
{
Console.WriteLine($"This is {typeof(Program)},t={t.GetType().Name},type={t}");
Console.WriteLine($"{t.Id} {t.Name}");
//return default(T);
}
public static void Show<T,S>(T t)
where T : people, ISports0, ISports1, new()
where S : new () //多个泛型可以直接约束
//where T : people, ISports0, ISports1, new()
//where S : T
//如果两个泛型约束相同可以这样写
{
Console.WriteLine($"This is {typeof(Program)},t={t.GetType().Name},type={t}");
Console.WriteLine($"{t.Id} {t.Name}");
//return default(T);
}
}
public class ShowClass_0<T> where T : ISports0
{
//泛型类约束
}
public class ShowClass_1<T,S> where T : ISports0 where S:ISports1
{
//多泛型参数的泛型类约束
}
public class people_0<T, S> : ShowClass_0<T>, ISports2<S>
where T:ISports0
where S:class
{
//使用了带有约束的父类或接口时,如果没有指明泛型类型,需要指明同父类或接口相同的约束
}
public class people_1<T, S> : ShowClass_0<Japanese>, ISports2<string>
{
//使用了带有约束的父类或接口时,如果指明了泛型类型,需要指明同父类或接口相同约束的类型
}
public interface ISports0
{
}
public interface ISports1
{
}
public interface ISports2<S>
where S : class
{
}
public class people: ISports0,ISports1
{
public int Id;
public string Name;
}
public class Chinese : people { }
public class Hubei : people { }
public class Japanese : people { }
}
泛型扩展:泛型缓存
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 泛型
{
class Program
{
static void Main(string[] args)
{
//每个不同的T都会生成一份不同的副本
//适合不同类型都需要缓存一份自身数据的场景,效率高
for (int i=0;i<5;i++)
{
Console.WriteLine(GenericCache<int>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<long>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<DateTime>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<string>.GetCache());
Thread.Sleep(10);
Console.WriteLine(GenericCache<Program>.GetCache());
Thread.Sleep(10);
}
}
}
//字典缓存,静态属性常驻内存,把传入类型作为键
//示例
public class DictionaryCache
{
private static Dictionary<Type, string> _TypeTimeDictionary = null;
static DictionaryCache()
{
Console.WriteLine("静态构造函数,全局只执行一次");
_TypeTimeDictionary = new Dictionary<Type, string>();//创建静态字典
}
public static string GetCache<T>()
{
Type type = typeof(T);
if (!_TypeTimeDictionary.ContainsKey(type))//是否不包含当前键
{
_TypeTimeDictionary[type] = string.Format("{0}_{1}",typeof(T).FullName,DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
}
return _TypeTimeDictionary[type];
}
}
//静态缓存,把传入类型作为键
//示例
public class GenericCache<T>
{
private static string _TypeTime = "";
static GenericCache()
{
Console.WriteLine("静态构造函数,全局只执行一次");
_TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
}
public static string GetCache()
{
return _TypeTime;
}
}
}
泛型扩展:协变逆变
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace 泛型
{
class Program
{
static void Main(string[] args)
{
//-------------------------------------------------------------------------------------------
//Bird bir_ = new Sparrow();//麻雀一定是一只鸟
//Sparrow spa = new Bird();//鸟不一定是一只麻雀,也有可能是其他鸟
//-------------------------------------------------------------------------------------------
//List<Bird> bir = new List<Bird>();
//List<Bird> bir1 = new List<Sparrow>();
//List集合不可以用子类实例化父类,因为编译器会编译成完全不同的两个类,也不存在父子关系
//-------------------------------------------------------------------------------------------
///协变
{
//-------------------------------------------------------------------------------------------
//协变:
// 可以让我们用子类实例化父类
// 协变的泛型参数只能作为返回结果,不能作为参数
//个人理解:
// 子类不包含父类,故子类实例父类不够完整
// 如果作为参数以父类的方式操作子类会造成不可预料的后果
// 因为操作的类型也可能是父类自身类型
// 所以只能作为返回结果
OutList<Bird> bir_0 = new OutList_<Bird>();
bir_0.Get();
OutList<Bird> bir_1 = new OutList_<Sparrow>();
bir_1.Get();
// 在协变中父类不可以实例化子类
//OutList<Sparrow> bir_2 = new OutList_<Bird>();
//-------------------------------------------------------------------------------------------
}
///逆变
{
//-------------------------------------------------------------------------------------------
//逆变:
// 可以让我们用父类实例化子类
// 逆变的泛型参数只能作为参数,不能作为返回结果
//个人理解:
// 父类包含子类,故父类拥有子类的完全属性
// 如果作为返回类型的话编译器识别不出当前泛型的具体类型
// 所以只能作为参数传递
InList<Sparrow> spa_0 = new InList_<Sparrow>();
spa_0.Show(new Sparrow());
InList<Sparrow> spa_1 = new InList_<Bird>();
spa_1.Show(new Sparrow());
// 在逆变中子类不可以实例化父类
//InList<Bird> spa_2 = new InList_<Sparrow>();
//-------------------------------------------------------------------------------------------
}
///协变+逆变
{
//-------------------------------------------------------------------------------------------
InOutList<Sparrow, Bird> ino_0 = new InOutList_<Sparrow, Bird>();
//协变,第二个泛型参数定义了out,所以可以子类实例化父类
InOutList<Sparrow, Bird> ino_1 = new InOutList_<Sparrow, Sparrow>();
//逆变,第一个泛型参数定义了in,所以可以父类实例化子类
InOutList<Sparrow, Bird> ino_2 = new InOutList_<Bird, Bird>();
//协变+逆变
InOutList<Sparrow, Bird> ino_3 = new InOutList_<Bird, Sparrow>();
//-------------------------------------------------------------------------------------------
}
}
}
public interface InOutList<in Tin,out Tout>
{
void Show(Tin tin);
Tout Get();
Tout Do(Tin tin);
}
public class InOutList_<Tin, Tout> : InOutList<Tin, Tout>
{
public Tout Do(Tin tin)
{
return default(Tout);
}
public Tout Get()
{
return default(Tout);
}
public void Show(Tin tin)
{
}
}
public interface OutList<out T>
{
//泛型参数带有out的称为协变,out只有在泛型和委托中才有协变的概念
T Get();
}
public class OutList_<T> : OutList<T>
{
//泛型接口的实现,注意泛型参数不能写错和漏写
public T Get()
{
//根据传递的参数返回默认值
return default(T);
}
}
public interface InList<in T>
{
//泛型参数带有in的称为逆变,in只有在泛型和委托中才有逆变的概念
void Show(T t);
}
public class InList_<T> : InList<T>
{
//泛型接口的实现,注意泛型参数不能写错和漏写
public void Show(T t)
{
//不做任何操作,只是为了演示
}
}
public class Bird
{
public int id { get; set; }
}
public class Sparrow : Bird
{
public string Name { get; set; }
}
}