.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<intstringdouble>//指定类型参数后才可以继承        :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());  }
原创粉丝点击