.NET编程(01)泛型
来源:互联网 发布:ios升级数据丢失 编辑:程序博客网 时间:2024/06/06 14:18
.NET编程01(泛型)
一:Object 类型:一切类型的父类,通过继承,子类拥有父类一切属性和行为;任何父类出现的地方,都可以用子类来代替;
用一个方法来完成多个方法做的事
// 普通方法类 public class CommonMethod { // 打印个int值 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> /// 打印个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); }
Typeof():用来获取某个类型
缺点:
第一:object是应用类型的,所以把值类型的参数传入ShowObject()方法时,就会存在装箱和拆箱,影响性能
第二:传入参数里面的属性值无法被访问到
第三:涉及到类型安全的问题
二:泛型(不属于语法糖,是ClR升级后才支持的语法)
用途:对于不同类型的参数,具有相同行为的时候,希望代码能重用起来,这时候使用泛型
原理: /// 延迟申明:申明方法的时候并没有指定参数类型(实际存在两个参数:T是类型参数,oParameter是真实参数),而是等到使用的时候在指定
/// 延迟思想:推迟一切可以推迟的
/// 编译的时候,类型参数编译为占位符,在程序真实运行的时候,JIT进行即时编译替换为真实类型
public class GenericMethod{ // 第一:泛型方法(方法名字后面带上尖括号,类型参数),尖括号类可以是任何没定义的任何字母或者类型,不要写关键字,不要把定义好的类写在里面 public static void Show<T>(T oParameter) { Console.WriteLine("This is {0},parameter={2},type={1}", typeof(CommonMethod), oParameter.GetType().Name, oParameter); }} class Program { static void Main(string[] args) { int iValue = 123; object ovalue=new object(); //第一:泛型方法调用 GenericMethod.Show<int>(ivalue); GenericMethod.Show(ivalue);//不指定类型参数,编译器自动推算 GenericMethod.Show<string>(ivalue);//此时报错,<类型参数>和参数类型:(ivalue)的类型必须吻合 GenericMethod.Show<object>(ovalue); }}
三:泛型类/接口
//泛型类public class GenericClass<M,T,S>{ public void Show(M m){}//可以作为参数 public T get(){}//可以作为返回值}
泛型接口
publuc interInface IStudy<T>{ T Study(T t);}
泛型委托
public delegate T GetHandler<T>();
普通类
public class Child :GenericClas<M,T,S>//报错普通类不能直接继承泛型类 :GenericClass<int,string,double>//指定类型参数后才可以继承 :IStudy<T>//报错普通类不能直接实现泛型接口 :IStudy<string>//指定类型后可以{ public string Study(string t){}}
泛型类
public class GenericChils<M,T>//等于申明了两个局部类型 M,T :GenericClass<M,T,String>//泛型类可以直接继承泛型类 :IStudy<T>//T和M都可以或者指定一个特定类型,除此之外不行,泛型类可以直接实现泛型接口{ T IStudy<T>.Study(T t){}}
四:泛型约束
public class People{ public int Id { get; set; } public string Name { get; set; } public void Hi(){ }}public class Chinese :People:ISports{ public void SayHi(){} public void Pingpang(){}}public interface ISports { void Pingpang(); }public class Constraint{ ///基类约束 /// 1: 基类约束,就可以访问基类的属性和方法 /// 2:被调用时, 参数必须是基类/子类 public static void Show<T>(T oParameter) where T:People{} **接口约束** public static void ShowInterface<T>(T oParameter) where T:ISports{} **接口+基类约束** public static void ShowBasic<T>(T oParameter) where T:People,ISports{} public static T Get<T>() //where T:Class//引用类型约束 //where T:struce//值类型约束 //where T:new()//无参数构造函数约束 { T t=new T(); return null;//应用类型默认值 return default(T):值类型默认值 }}
泛型方法的约束的调用:
People people = new People()Chinese chinese = new Chinese()Constraint.Show<People>(People p)Constraint.Show(people )Constraint.Show<Chinese >(Chinese p)Constraint.Show(chinese )Constraint.ShowInterface(people)
五:泛型的协变/逆变(out/in):只能放在接口或者委托的参数前面,类没有协变逆变
out 协变 convariant 修饰返回值
in 逆变 contravariant 修饰传入参数 IEnumerable<int> Action<int>
第一:协变
定义两个普通类
public class Bird{public int ID{get;set;}}public class Sparrow:Bird{public string Name{get;set;}}List<Bird> b1list=new List<bird>();------编译正确List<Bird> B2list=new List<Sparrow>();------编译错误,因为list<Bird>和List<Sparrow>不是父子关系,没有继承关系但是实际工作中会有这种需要(用父类集合来接受子类的集合)一般的写法:List<Bird> B3list=new List<Sparrow>().select(c=>(Bird)c).ToList();-----编译正确,类型进行了强转
简单的写法:
IEnumerable<Bird> b1=new List<bird>();-----协变IEnumerable<Bird> b2=new List<Sparrow>();---协变(实际上也存在类型的的转换,只不过是编译器来做,减少了代码量)以上写法采用协变使用系统提供的IEnumerable<out T>public interface IEnumerable<out T> : IEnumerable --- 系统对IEnumerable<out T>的定义使用List来接受子类集合会报错是因为,系统本身本没有对list进行协变定义public class List<T>:IList<T>,IEnumerable<T>..........----- 系统对List<T>的定义 参数没有Out原因:List出现在.net2.0版本,而IEnumerable<out T>出现在C#4.0版本,两个不是属于同一个时期出现
自定义协变接口
Public interface ICustomerListOut<out T>{ T Get();-----正确 void Show(T t)----报错,T不能作为传入参数,只能是返回结果;}//类没有协变逆变public class CustomerListOut<T>:ICustomerListOut<T>{ public T Get(){return default(T);}}使用:ICustomerListOut<Bird> b=new CustomerListOut<Bird>();ICustomerListOut<Bird> b=new CustomerListOut<Sparrow>();
第二:逆变
自定义逆变接口
Public interface ICustomerListOut<in T>{ //T Get();-----报错,T只能作为传入参数,不能是返回结果; void Show(T t)----正确}public class CustomerListOut<T>:ICustomerListOut<T>{ public void Show(T t){}}使用: ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>(); ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();
第三:逆变+协变(实际工作中使用很少,一般使用系统很少自己定义,系统自带
Func<in T,out Tresult>) public interface IMyList<in inT, out outT> { void Show(inT t); outT Get(); outT Do(inT t); } 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); } }
使用: 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>();//协变+逆变
第六:泛型的缓存
一般采用字典缓存:定义一个静态属性
/// 字典缓存:静态属性常驻内存
public class DictionaryCache { private static Dictionary<string, string> _TypeTimeDictionary = null; static DictionaryCache() { Console.WriteLine("This is DictionaryCache 静态构造函数"); _TypeTimeDictionary = new Dictionary《string, string>(); } public static string GetCache<T>() { Type type = typeof(T); if (!_TypeTimeDictionary.ContainsKey(type.Name)) { TypeTimeDictionary[type.Name] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } return _TypeTimeDictionary[type.Name]; } }
第二:泛型缓存
原理:利用泛型每次在运行时Jit即时编译生成不同的副本
使用场景:用来保存固定数据,适合不同类型,需要缓存一份数据的场景,
优点:效率高
缺点:不能清除被回收
/// 每个不同的T,在运行的时候JIT都会生成一份不同的副本,用于保存不同的T
public class GenericCache<T> { static GenericCache() { Console.WriteLine("This is GenericCache 静态构造函数"); TypeTime=string.Format({0}_{1}",typeof(T).FullName,DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } private static string _TypeTime = ""; public static string GetCache() { return _TypeTime; } }
调用:
for (int i = 0; i < 5; i++) { Console.WriteLine(GenericCache<int>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<long>.GetCache()); }
- .NET编程(01)泛型
- .net 安全编程(序)
- .NET多线程编程(2)
- NET特性编程(Attribute)
- .NET编程(02) 反射
- .NET编程(04)特性
- .NET学习(7)ADO.NET进行数据库编程
- /ASP.NET时尚编程百例01
- 最佳ASP.NET编程习惯(转载)
- .net编程中的一些技巧(一)
- .net编程中的一些技巧(二)
- .NET多线程编程(3):线程同步
- .NET多线程编程(3):线程同步
- 最佳ASP.NET编程习惯(转载)
- .NET多线程编程(3):线程同步
- .NET多线程编程(3):线程同步
- .NET多线程编程(3):线程同步
- .NET多线程编程(3):线程同步
- 3-1 Point类的构造函数
- 分类精度评价
- 第三周第一节课
- Red Hat As6上安装11.2.0.1 RAC 遇到root.sh执行报错
- Nginx+Tomcat+Redis实现负载均衡与Session共享之二 — redis下载安装
- .NET编程(01)泛型
- Linux主机之间传输文件的几种方法对比
- Linux下nginx安装
- 服务器上配置https协议
- 微服务可能应用的设计模式
- hihocoder#1506 : 投掷硬币(概率DP)
- 百度地图几个常用的鼠标事件
- echarts环状图
- 解读The Python Tutorial(七)