zoukankan      html  css  js  c++  java
  • 读书笔记: 泛型 CLR via C#

     

      为什么泛型?

      面向对象的语言好处是使得程序员可以很方便地重用代码, 在面向对象中程序员可以写一个子类去继承自一个父类,写不同的程序能够重用以前的代码, 会减少很多代码的工作量。

      但是算法能不能重用呢? 答案是肯定的, CLR提供了一个算法重用的机制, 就是泛型。

      算法重用的例子, 参考List<T>类型, System.Collections.Generic中定义。

       

      泛型类型和继承

      我们使用两段代码来说明:

      Internal sealed class Node<T>

      {

      Public T m_data;

      Public Node<T> m_next;

       

      Public Node(T data):this(data, null)

      {

      m_data=data;

      }

       

      Public Node(T data, Node<T> next)

      {

      m_data=data;

      m_next=next;

      }

       

      Public override String ToString()

      {

      return m_data.ToString() + ((m_next!=null)? m_next.ToString(): String.Empty);

      }

      }

       

      有了这样的类型以后, 我们就可以去建造一串有字符组成的链。

      Private static void SameDataLinkedList()

      {

      Node<Char> head=new Node<Char>('C');

      head=new Node<Char>('B', head);

      head=new Node<Char>('A', head);

       

      Console.WriteLine(head.ToString());

      }

       

      上面是的链上的数据都是同一类型的, 如果要把不同类型的数据放在一个链里, 可以怎样实现呢? 是的, 可以使用Object 作为类型的参数传进去, 代码如下。

      Private static void DifferentDataLinkedList()

      {

      Node<Object> head=new Node<Object>('C', null);

      head = new Node<Object>(DateTime.Now, head);

      head= new Node<Object>("This is String", head);

      Console.WriteLine(head.ToString());

      }

       

      但是, 如果是Object的类型的话, 我们值类型的数据要传给Object的参数会使用装箱操作, 对性能的影响非常大。还有一种方法就是使用泛型的继承实现, 性能会提高很多, 代码如下:

      Internal class Node

      {

      Protected Node m_next;

       

      Public Node(Node next)

      {

      m_next=next;

      }

      }

       

      Internal class TypeNode<T>: Node

      {

      Public T m_data;

       

      Public TypeNode(T data, Node next):base(next)

      {

      m_data=data;

      }

       

      Public TypeNode(T data): this(data, null)

      {

      m_data=data;

      }

       

      Public override String ToString()

      {

      return m_data.ToString() + ((m_next!=null)? m_next.ToString(): String.Empty);

      }

      }

       

      有了以上代码, 我就可以这样定义我的链了:

      Internal static void DifferentDataLinkedList()

      {

      Node head=new TypeNode<Char>('C');

      head= new TypeNode<DateTime>(DateTime.Now, head);

      head=new TypeNode<String>("This is String", head);

      Console.WriteLine(head.ToString());

      }

       

      这样实现的泛型继承的好处: 类型安全 不需要装箱。

       

      泛型标识

      泛型的写法的确是麻烦, 一堆的< >, 不管是读和写都很麻烦, 有什么方法能走点近道呢? 答案有两种方法: 继承 使用Using 关键字。

      如果我们在程序中用的了List<DateTime> dtl=new List<DateTime>(); 这样的代码很多的话, 我们就能写一个DateTimeList的类来继承List<DateTime>

      Interanl class DateTimeList: List<DateTime>{

      //这里边不需要写代码

      }

      所以在程序中我们就可以使用DateTimeList来替换所有使用到List<DateTime>的地方。

       

      第二种方法使用Using关键字

      我们可以给List<DateTime>声明一个别名DateTimeList, 如下代码:

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

      然后我们就可以在程序中使用DateTimeList这个类型了。

       

      两种方法的区别是第二种方法中, DateTimeListList<DateTime>完全等价, 而在第一种方法中, 有如下注意点: 任何使用类型List<DateTime>的地方都可以使用DateTimeList替换, 但是使用DateTimeList的地方不能使用List<DateTime>替换, 因为两者是继承关系而非等价关系。

       

      优化代码编译过程

    1. 在同一个应用程序域中的两个Assembly如果都是用到了同一种类型List<DateTime>, 那么这两个在CLR中只会编译一次。
    2. 所有以引用类型作为参数的, 这些code都可以被共享, 因为不管是List<String> 还是List<Stream>, 他们都是一个指针(要么是32bits, 要么是64bits), 这个指针指向存储在堆上的数据。 所有的指针都是相同的操作(即CPU指令相同)。
    3. 注: 值类型就不是这样的, 因为值类型的大小不一样, 即使大小一样的话, 操作这些值的指令也不同。

  • 相关阅读:
    第三个Sprint ------第十一天
    第三个Sprint ------第十天
    第三个Sprint ------第九天
    第三个Sprint ------第八天
    第三个Sprint ------第七天
    第三个Sprint ------第六天
    第三个Sprint ------第五天
    第三个Sprint ------第四天
    第三个Sprint ------第三天
    第三个Sprint ------第二天
  • 原文地址:https://www.cnblogs.com/qixue/p/2121778.html
Copyright © 2011-2022 走看看