zoukankan      html  css  js  c++  java
  • 有关泛型的用法

      泛型(Generic)是对CLR类型系统的扩展,用于定义未指定某些细节的类型。实际上,代码本身就是泛型。

      使用泛型可以避免以下两个常见的问题:代码冗余和困扰开发人员的含混不清的编译器错误。假设集合类SortedList是Object引用的集合,GenericSortedList<T>是任意类型的集合,使用泛型具有以下明显的优点。

      (1)类型安全

        当用户向SortedList类型的集合内添加String时,String会隐式强制转换为Object。同样,如果从该列表中检索String对象,则它必须在运行时从Object引用强制转换到String引用。这样就会造成编译时缺少类型安全,从而使编写的代码容易出错。相反,如果使用GenericSortedList<String>(T的类型被设置为String),就会使所有的添加和查找方法是用String引用。这样在编译时就可以检查元素的类型是否正确。

      (2)二进制代码重用

        为了进行维护,开发人员可以选择使用SortedList,通过从它派生SortedListOfString来实现编译时的类型安全。此方法有一个问题,那就是必须对于每个需要类型安全列表的类型都编写新代码,而这会很快变成非常费力的工作。使用GenericSortedList<T>,需要执行的全部操作就是将具有所需元素类型的类型实例化为T。泛型代码还有一个附加价值,那就是它在运行时生成,因此,对于无关元素类型的两个扩展(如GenericSortedList<String>和GenericSortedList<FileStream>)能够重新使用同一个实时(JIT)编译代码的大部分。CLR只是处理细节就可以了,从而使代码不再臃肿。

      (3)性能

        如果能在编译时进行类型检查,而不是在运行时进行检查,则显然会大大增强系统的性能。在托管代码中,引用和值之间的强制转换既会导致装箱又会导致拆箱,而且避免这样的强制转换可能会对性能产生同样的负面影响。如果对一个由一百万个整数组成的数组进行快速排序法基准测试,就会发现泛型方法比非泛型方法快得多。这是由于完全避免了对这些值进行装箱。如果针对由字符串引用组成的数组进行同样的排序,则由于无需在运行时执行类型检查,因此使用泛型方法后大大提高了性能。

      (4)清晰性

        泛型的清晰性体现在许多方面。约束是泛型的一个功能,它会禁止对泛型代码进行不兼容的扩展;使用泛型,也不再有困扰C++模板用户的含混不清的编译器错误。在GenericSortedList<T>中,集合类将有一个约束,该约束使集合类只处理可进行比较并依此进行排序的T类型。同样,通常可以使用名为类型推理的功能来调用泛型的方法,而无需使用任何特殊语法。当然,编译时类型安全可以使应用程序代码更加清晰。

      

    泛型的定义

      CLR支持多种编程语言,因此,CLR泛型也有多种语法。但是,无论采用哪种语法,用一种面向CLR的语言编写的泛型代码也可以由其他面向CLR的语言编写的程序使用。

      泛型的定义代码语法为:

      [访问修饰符] [返回类型] 泛型支持类型泛型名称<类型参数列表>

       

      其中,CLR支持泛型类、结构、方法、接口和委托等。泛型名称要符合标示符的定义。尖括号表示类型参数列表,尖括号紧跟在泛型类类型或成员的名称后面。同样,在类型参数列表中有一个或多个类型参数,形式如<T,U,…>。

    例1:定义一个泛型类

    1 class Node <T>
    2 {
    3 T data;
    4 Node<T>next;
    5 }
    6  

    例2:定义一个泛型方法

    1 void Swap<T>(ref T item1, ref T item2)
    2 {
    3 T temp=item1;
    4 item1=item2;
    5 item2=temp;
    6 }
    7  

    泛型的引用

      引用泛型时,也可以将未指定的类型变成系统能够识别的指定的类型。例3和例4分别是对例1和例2的引用示例。

    例3:引用一个泛型类

    1 class Node8Bit:Node<Byte>
    2 {
    3
    4 }
    5  

    例4:引用一个泛型方法

    1 Decimal d1=0,d2=2;
    2 Swap<Decimal>(ref d1,ref d2);

      通过例子可以看出,定义一个类或者方法时,可以利用泛型<T>代表任何一种类型,而在引用时再指定具体类型。在例6中,当代码调用泛型方法Swap<T>时,C#编译器会自动将定义的泛型转换为引用代码中指定的类型,从而大大简化了编程人员代码书写的工作量。

      由于泛型<T>可以代表任何一种类型,因此只定义一次方法的参数类型就能实现所有类型的引用。例如,例6中的d1可能是int型、float型等(d2同样如此),如果不使用泛型,就需要写出很多重载的Swap方法,使代码既臃肿,又不易阅读,同时也增加了编译工作量。由此可以看出,泛型的优点是显而易见的。

    常用的泛型集合

      在.NET Framework类库中,System.Collections.Generic和System.Collections.ObjectModel命名空间中提供了很多泛型集合类。许多泛型集合类型是泛型类型的直接模拟。表1列出了常见的泛型集合类与非泛型集合类的对应关系。

    表1         常见的泛型集合类及对应的非泛型集合类

    1. List<T>

      List泛型类表示可通过索引访问的对象的强类型列表,提供用于对列表进行搜索、排序和操作的方法。常用方法如下。

      Add方法:将指定值的元素添加到List<>中。

      Insert方法:在列表的中间插入一个新元素。

      Contains方法:测试该列表中是否存在某个元素。

      Remove方法:从列表中移除带有指定键的元素。

      Clear方法:移除列表中的所有元素。

    2. Dictionary<Tkey,Tvalue>

      Dictionary泛型类提供了一组键到一组值的映射。字典中的每个添加项都由一个值及其相关联的键组成,通过键来检索。常用方法如下:

      Add方法:将带有指定键和值的元素添加到Dictionary<,>中。

      TryGetValue方法:获取与指定键相关联的值。

      ContainsKey方法:确定Dictionary<,>中移除带有指定键的元素。

      Remove方法:从Dictionary<,>移除带有指定键的元素。

    3. Queue<T>

      Queue泛型类表示对象的先进先出集合。

      常用方法如下:

      Enqueue方法:将指定元素插入列尾。

      Dequeue方法:队列首元素出列。

    4. Stack<T>

      Stack泛型类表示同一任意类型的实例的大小可变的后进先出(LIFO)集合。

      常用方法如下:

      Push方法:将指定元素插入栈项。

      Pop方法:将栈项元素弹出。

    5. SortedList<Tkey,Tvalue>

      SortedList泛型类表示键/值对的集合,这些键/值对基于关联的IComparer实现按照键进行排序。

      常用方法如下:

      Add方法:将带有指定键和值的元素添加到SortedList<,>中。

      TryGetValue方法:获取与指定的键相关联的值。

      ContainsKey方法:确定SortedList<,>中是否包含指定的键。

      Remove方法:从SortedList<,>中移除带有指定键的元素。

    例5:现有一个活期存款账户类Account,为其提供处理业务的Customers类有一个方法CreateAccount(账户名,开户金额),试使用SortedList<,>创建泛型对象,并判断是否存在账户“张三”,若不存在,则创建账户;若存在,则为其追加存款。

    主要代码如下所示:

    代码
    1 using System;
    2 using System.IO;
    3 using System.Collections.Generic;
    4 namespace GenricExample
    5 {
    6 public class Account
    7 {
    8 private string accountName;
    9 private int accountvalue;
    10 public string AccountName
    11 {
    12 get
    13 {
    14 return accountName;
    15 }
    16 set
    17 {
    18 accountName=value;
    19 }
    20 }
    21 public int AccountValue
    22 {
    23 get
    24 {
    25 return accountvalue;
    26 }
    27 set
    28 {
    29 accountvalue=value;
    30 }
    31 }
    32 }
    33 public class Customers
    34 {
    35 public void CreateAccount(string name,int value1)
    36 {
    37 Account acc=new Account();
    38 acc.AccountName=name;
    39 acc.AccountValue=value1;
    40 }
    41 }
    42 class Porgram
    43 {
    44 static void Main(string[] args)
    45 {
    46 SortedList<string,Account> accounts=new SortedList<string,Account>();
    47 Customers customs=new Customers();
    48 if(accounts.ContainsKey("aa")==false)
    49 {
    50 //如果无此账户,创建账户,并将存款作为开户金额
    51 Account account=new Account();
    52 customs.CreateAccount("张三",1000);
    53 accounts.Add("张三",account);
    54 }
    55 else
    56 {
    57 //如果有此账户,在现有账户上追加存款
    58 Account account=accounts["张三"];
    59 //account追加存款操作
    60 }
    61 }
    62 }
    63 }
    64
  • 相关阅读:
    《JSP2.0 技术手册》读书笔记六JSP语法与EL
    《Spring 2.0技术手册》读书笔记一Spring与eclipse的结合
    二元查找树转为双向链表
    《Jsp2.0技术手册》读书笔记补充web.xml详解及listener,filter,servlet加载顺序
    《JSP2.0技术手册》读书笔记三Filter
    《Spring2.0技术手册》读书笔记二理念
    Swift构造器链
    Swift函数_外部参数名,
    Swift数据类型_整型和浮点型
    Swift函数_默认参数
  • 原文地址:https://www.cnblogs.com/ZHF/p/1778183.html
Copyright © 2011-2022 走看看