好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

泛型

泛型

以下几节中我将对C#2中增加的最重要的特性进行介绍。

  1)泛型---作为C#2最重要的新特性(同时也是.NET2.0的CLR中最重要的新特性),泛型实现了类型和方法的参数化。

  2)可空类型---值类型没有“值不存在”的概念。有了可空类型之后,就可以表示“缺少一个有意义的值”。

  3)委托---虽然委托在CLR的级别上没有任何变化,但C#2使它们使用起来更容易。除了语法得到了一些简化,匿名方法的引入,还引导我们采取更“函数化”的编程风格---这个趋势在C#3中得到了延续。

  4)迭代器---虽然一直以来,都可以利用C#的foreach语句来简单地使用迭代器,但C#1中,它实现起来却是一件让人痛苦的事情。C#2编译器能在幕后帮你构建一个状态机,从而隐藏了大量复杂性。

  对大多数人来说,泛型将成为C#2最重要的新特性。他们增强了性能,使代码更富有表现力,而且将大量的安全检查从执行时转移到了编译时进行。从根本上说,泛型实现了类型和方法的“参数化”,就像在普通方法调用中,经常要用参数来告诉他们使用什么值。同样,泛型的类型和方法也可以让参数告诉他们使用什么类型。

  搞懂泛型的方方面面不是一件容易的事情,这样我还是通过简单的例子来学习泛型。 先来看看.NET2.0提供的一个集合类:Dictionary<TKey, TValue>。

 using   System;
  using   System.Collections.Generic;
  using   System.Text.RegularExpressions;

  class   泛型字典
{
      static  Dictionary< string ,  int > CountWords( string   text)
    {
          //  创建单词到频率的新映射,它将有效统计每个单词在一段给定文本中出现的频率 
        Dictionary< string ,  int >  frequencies;
        frequencies  =  new  Dictionary< string ,  int > ();
          /*  将文本分解成单词,对于每个单词,都检查它是否已经存在映射中,
        如果是则增加现有计数;否则就为单词赋予一个初始计数1   */ 
         string [] words = Regex.Split(text,  @"  \W+  "  );
          foreach  ( string  word  in   words)
        {
              if   (frequencies.ContainsKey(word))
            {
                  /*  这里需要注意下:负责递增的代码不需要执行到int的强制类型转换,就可以执行加法运算:
                取回的值在编译时已经知道是int类型。使计数递增的步骤实际是先对映射的索引器执行一次取值操作,
                然后增加,然后对索引器执行赋值操作。  */  
                frequencies[word] ++ ;
            }
              else  
            {
                frequencies[word]  =  1  ;
            }
        }
          return   frequencies;
    }


      public   static   void   Main()
    {
        Console.Write(  "  Please input the text:  "  );
          string  text =  Console.ReadLine();

        Dictionary < string ,  int > frequencies =  CountWords(text);
          //  打印映射中的每个键/值对。 
         foreach  (KeyValuePair< string ,  int > entry  in   frequencies)
        {
              string  word =  entry.Key;
              int  frequency =  entry.Value;
            Console.WriteLine(  "  {0}:{1}  "  , word, frequency);
        }

         
        Console.Read();
    }
} 

运行效果如下图:

   既然我们已经看了一个例子,首先让我们来看一下Dictionary<TKey, TValue>的真正含义,什么是TKey和TValue,而且为什么要用尖括号把他们封闭起来。 有两种形式的泛型:泛型类型(包括类、接口、委托和结构)和泛型方法。两者都是表示API的基本方法(不管是指一个泛型方法还是一个完整的泛型类型)。

  类型参数是真实类型的占位符。在泛型声明中,类型参数要放在一对尖括号内,并且要以逗号分隔开。所以在Dictionary<TKey, TValue>中,类型参数是TKey和TValue。在使用泛型类型或方法时,需要使用真实的类型代替,这些真实的类型称为类型实参(type argument),在上述代码中类型实参是string(代替TKey)和int(代替TValue)。

  如果没有为任何类型参数提供类型实参,声明的就是一个未绑定泛型类型(unbound generic type)。 如果指定了类型实参,该对象就成为一个已构造类型(constructed type)。我们知道,类型(无论是否是泛型)可以看做是对象的蓝图。同样,未绑定泛型类型是已构造类型的蓝图,它是一种额外的抽象层。关系如下图:

   更复杂的是,已构造类型可以是开放或封闭的。开放类型(open type)还包含了类型参数,而封闭类型(closed type)则不是开放的,类型的每个部分都是明确的。在C#代码中,唯一能看见未绑定泛型的地方(除了作为声明之外)就是在typeof操作符内。类型参数“接收”信息,类型实参“提供”信息。这个思路与方法参数/方法实参是一样的。只不过类型实参必须为类型,而不能为任意的值。只有在编译时才能知道类型实参的类型,它可以是(或包含)相关上下文中的类型参数。

  读者可以具体参考下Dictionary<TKey, TValue>的内容,有助于进一步理解,这里就不做啰嗦的说明了。

 

泛型的发音 在向其他人描述泛型类型时,通常使用of来介绍类型参数或实参,因此List<T>读作list of T。当有多个类型参数时,可以用一个适合整个类型含义的单词来分隔他们,例如:我经常用dictionary of string to int 来强调映射的部分,而不会使用 tuple of string and int。

类型参数命名规范 虽然可以使用带有T、U和V这样的类型参数的类型,但从中根本看不出实际指的是什么,也看不出他们应该如何使用。相比之下,像Dictionary<TKey, TValue>这样的命名就好的多,TKey明显表示keys的类型,而TValue代表values的类型。如果只有一个参数类型,而且它的含义很清楚,那么一般使用T(List<T>就是一个很好的例子)。如果有多个类型参数,则应根据含义来命名,并用T前缀来指明这是一个类型参数。

 

分类:  C#

作者: Leo_wl

    

出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于泛型的详细内容...

  阅读:91次