zoukankan      html  css  js  c++  java
  • 【Clr in c#】泛型

      使用泛型的好处是“代码重用”,极大的提高了开发效率,泛型为开发者提供了以下优势:

        1,源代码保护  算法的源代码不需要提供给使用泛型算法的开发人员,使用c++模板的泛型技术需要提供。(目前c++模板的泛型技术了解较少)

        2,类型安全    给泛型算法指定类型时,编译器能理解开发者意图,只有兼容类型能通过,不兼容的时候编译时候会报错。

        3,更清晰的代码  由于编译器强制类型的安全性,减少源代码中必须进行的转型次数,使得代码容易维护和编写。例如:DateTime dt=dtList[0];从DateTime的集合中按照索引取出来的值可以直接赋值给DateTime类型,不需要转型。

        4,更佳的性能 在操作值类型时候,非泛型集合会造成装箱、拆箱操作,会造成托管堆上的内存分配,会造成频繁的垃圾回收,影响性能。

        补充:对于泛型方法,约束父类类型,与参数直接传递父类,在没有返回值的情况下是没有区别的,假如有需要返回传入的类型,则用泛型方法比较合适,因为通过泛型方法返回的类型不需要经过类型转换  http://bbs.csdn.net/topics/380050195

     1 public class AA{}
     2 public class BB:AA{}
     3 
     4 
     5 public void GetText<T>(T t) where T:AA
     6 {
     7 }
     8  9 public void GetText(AA x)
    10 {}之间是等效的,没有区别。
    11 
    12 
    13 public T GetText<T>(T t) where T:AA
    14 {
    15 }
    16 public AA GetText(AA x)
    17 在调用的地方是有区别的
    18 
    19 BB b=new BB();
    20 var rtGetText=GetText<BB>(b);
    21 var rtGetText2=(BB)GetText(B);//需要进行一次类型转换
    View Code

    1.泛型基础结构

      1.1 开放类型和封闭类型

          具有泛型类型参数的类型称为开放类型。

            不能创建实例。例如Dictionary<,>,没有指定参数,目前尚不清楚这个开放类型有什么用。

          所有类型实参传递的都是实际数据类型为封闭类型。

            使用约束无法将类型实参限制为某一类型,可以用一个静态构造器来保证类型。如下

          

    internal sealed class GenericTypeThatRequiresAnEnum<T>{
      static   GenericTypeThatRequiresAnEnum(){
        if(!typeof(T).IsEnum){
          throw new ArgumentException("T must be an enumerated type");
        }
      }
    }

      1.2泛型类型的继承

        泛型类型仍然是类型,它能从其他任何类型派生。

        public class Node1<T>
        {
            public T m_data;
            public Node1<T> m_next;
            public Node1(T data) : this(data, null) { }
            public Node1(T data, Node1<T> next)
            {
                m_data = data;
                m_next = next;
            }
            public override string ToString()
            {
                // ABC
                return m_data.ToString()+((m_next!=null)?m_next.ToString():null);
            }
        }

      上面例子必须是相同数据类型下使用,加入链表需要多个m_data为多种类型的时候这种结构将无法满足,这时候我们可以考虑抽出一个非泛型的基类,这样继承的泛型就可以指定多种类型。这是一个泛型应用的技巧。

    public class Node2
        {
            protected Node2 m_next;
    
            public Node2(Node2 next)
            {
                m_next = next;
            }
        }
    
       public class TypeNode<T> : Node2 {
            public T m_data;
            public TypeNode(T data,Node2 next):base(next){
                m_data = data;
            }
            public TypeNode(T data):this(data,null){
            }
            public override string ToString()
            {
                // Tody is 时间。
                return m_data.ToString() + ((m_next != null) ? m_next.ToString() : null);
            }
        }

    1.3泛型类型的同一性

      这种性质不经常用,这里简单记一下只当了解。

      简化泛型的写法多封装一层去除"<"">"。

      class DateTimeList:List<DateTime>{

      //这里不需要放入任何代码。

    }

    这样使用的时候就没有<,>符号了。

    DateTimeList dt=new DateTimeList();

    这只是表面方便了,绝对不要单纯出于增强代码可读性目的定义一个新类,事实上也不会这么做,但是这样写会丧失同一性和相等性,如下代码为Flase

    Boolean sameType=(typeof(List<DateTime>)==typeof(DateTimeList));

    可以通过使用using指令弥补相等性,添加如下结果为True;

    using DateTimeList=System.Collections.Generic.List<System.DateTime>;

    1.4代码爆炸

      使用泛型类型参数的一个方法在JIT(即时编译)编译时,Clr获取方法的IL,用指定的实参进行替换,创建恰当的本地代码,缺点是CLR要为每种不同的方法、类型组合生成本地代码,可能造成应用程序集显著增大,损坏性能,称之为 代码爆炸。

      但是CRL内建了一些优化措施,缓解代码爆炸。所有程序集使用List<DateTime>时候,只会生成一次,认为所有引用类型实参都是完全相同,List<String>和List<Stream>可以公用,之所以会这样,是因为所有引用类型的实参或者变量实际都是指向堆上的对象指针,而指针全部都是以相同的方式来操作。

    2,泛型接口

      泛型接口的一个例子是IComparable接口,在接口里详细写

    3,泛型委托

      建议使用泛型的Action和Func委托,会在以后的委托中细说

    4,委托和接口的逆变和协变泛型类型实参

      不变量(invariant)表示泛型类型不可变。

      逆变量(contravariant)表示泛型类型参数可以从一个基类更改为该类的派生类,用in关键字标记,只出现在输入位置。

      协变量(covariant) 表示泛型类型可以从一个派生类更改为它的基类型,用out关键字标记,只出现在输出位置。

      public delegate TResult Func<in T,out TResult>(T arg);

      Func<object,ArgumentException> fn1=null;

      func<string,Exception> fn2=fn1;//这里不需要显示转换,因为逆变量,协变量

      调用委托Exception e=fn2("");

      

      使用要获取泛型参数和返回值的委托时,建议尽量使用in和out关键字,因为不会有不良反应。

      泛型接口和泛型委托一样也可以用out和in。

    5,泛型方法

       用一个例子介绍下泛型的定义,下面一个类型定义了一个类型参数,一个方法定义了它自己的专用类型参数。

      

    class GenericType<T>{
      private T m_value;
      public GenericType(T value){m_value=value;}
      public TOutput Coverter(TOutput)(){
            TOutput  result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput ));
          return   result;
      }  
    }

      下面写一个比较经典常用的泛型方法,2个参数互换

    private static void Swap<T>(ref T o1,ref T o2){
      T temp=o1;
      o1=o2;
      o2=temp;    
    }

    6泛型约束

      确保使用当前泛型是自己想要的类型。

     例如如下方法,在类型没有提供CompareTo方法时候会报错。

     private static T Min<T>(T o1,To2){

        if(o1.CompareTo(o2)<0)

          return o1;

        return o2;

      }

       这个时候我们就需要在该泛型方法添加泛型约束。

     private static T Min<T>(T o1,To2) where T:IComparable<T>{

        if(o1.CompareTo(o2)<0)

          return o1;

        return o2;

      }

    泛型约束主要分为3种。

    1,主要约束   主要约束可以是一个引用类型,实参必须与约束相同或者派生,

    例如where T:Stream ,使用该泛型方法必须是Stream 类型或者其派生类型。

    where T:Class,使用该泛型方法必须是引用类型。

    2,次要约束   次要约束代表的是一个借口类型,指定的参数必须实现所有接口约束例如 where T:IComparable<T>

    3,构造器约束    指定的实参必须实现公共无参构造器的一个非抽象类型where T:New()

      

     下面是项目中用到的一个泛型方法,模板反序列化。使用了Newtonsoft.Json

            public T GetTemplateData<T>() where T : TemplateData
            {
                if (!string.IsNullOrEmpty(TemplateDataJsonStr))
                {
                    T obj = (T)JsonConvert.DeserializeObject(TemplateDataJsonStr, typeof(T));
                    obj.CheckField();
                    return obj;
                }
                else return null;
                
            }
            public void SetTemplateData(TemplateData templateData) 
            {
               TemplateDataJsonStr= JsonConvert.SerializeObject(templateData);
            }

      

  • 相关阅读:
    Java Lambda表达式初探
    解开lambda最强作用的神秘面纱
    常用正则表达式
    js,java时间处理
    Java 8新特性探究(二)深入解析默认方法
    Java 8里面lambda的最佳实践
    lambda表达式和闭包
    Lambda语法篇
    lambda表达式
    依赖注入和控制反转的理解
  • 原文地址:https://www.cnblogs.com/m7777/p/4075280.html
Copyright © 2011-2022 走看看