• 四、泛型(第二部分)


    1.泛型的概述

      .NET自从2.0版本开始就支持泛型。泛型不仅是C#编程语言的一部分,而且与程序集中的IL(中间语言)代码紧密地集成。有了泛型,就可以创建独立于被包含类型的类和方法了。我们不必给不同的类型编写功能相同的许多方法或类,只创建一个方法或类即可。

      另一个减少代码的选项是使用Object类,但Obejct类不是类型安全的。泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型。这就保证了类型安全性:如果某个类型不支持泛型类,编译器就会出现错误。

      泛型不仅限于类,本章还将介绍用于接口和方法的泛型。

      泛型并不是一个全新的结构,其它语言中有类似的概念。例如,C++模版就与泛型相似。但是C++模版和.NET泛型之前有一个很大的区别。对于C++模版,在用特定的类型实例化模版时,需要模版的源代码。相反,泛型不仅是C#的一种结构,而且是CLR定义的。所以,即使泛型类是在C#中定义的,也可以在Visual Basic中用一个特定的类型实例化该泛型。

      下面几节介绍泛型的优点和缺点:

       *性能

       *类型安全性

             *二进制代码重用

             *代码的扩展

             *命名约定

    1.性能

      泛型的一个主要有点是性能。

      值类型存储在栈上,引用类型存储在堆上。C#类是引用类型,结构是值类型。.NET很容易把值类型转换为引用类型,所以可以在需要对象(对象是引用类型)的任意地方使用值类型。例如,int可以赋予一个对象。从值类型转换为引用类型称为封箱。如果方法需要把一个对象作为参数,同时传递一个值类型,装箱操作就会自动进行。另一方面,装箱的值类型可以使用拆箱操作转换为值类型。在拆箱时,需要使用类型强制转换运算符。

      下面的例子显示了System.Collections名称控件中的ArrayList类。ArrayList存储对象,Add()方法定义为需要把一个对象作为参数,所以要装箱一个整数类型。在读取ArrayList中的值时,要进行拆箱,把对象转换为整数类型。可以使用类型强制转换运算符把ArrayList集合的第一个元素赋予变量il,在访问int类型的变量i2的foreach语句中,也要使用类型强制转换运算符:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication7
    {
        class Program
        {
            static void Main(string[] args)
            {
                var myList = new ArrayList();
                myList.Add(44);
                myList.Add(55);
    
                int il = (int)myList[0];
    
                foreach (int i2 in myList)
                {
                    Console.WriteLine(i2);
                }
    
                Console.ReadKey();
            }
        }
    }

      装箱和拆箱操作很容易使用,但性能损失比较大,遍历许多项时尤其如此。

      System.Collections.Generic名称空间中的List<T>类不使用对象,而是在使用时定义类型。在下面的例子中,List<T>类的泛型类型定义为int,所以int类型在JIT编译器动态生成的类中使用,不再进行装箱和拆箱操作:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication7
    {
        class Program
        {
            static void Main(string[] args)
            {
                var myList = new List<int>();
                myList.Add(132456789);
                myList.Add(111111);
    
                int il = myList[0];
    
                foreach (int i2 in myList)
                {
                    Console.WriteLine(i2);
                }
    
                Console.ReadKey();
            }
        }
    }

     

    2.类型安全

      泛型的另一个特性就是类型安全。与ArrayList类一样,如果使用对象,就可以在这个集合中添加任意类型。下面的例子在ArrayList类型的集合中添加一个整数、一个字符串和一个MyClass类型的对象。

      如果这个集合使用下面的foreach语句迭代,而该foreach语句使用整数元素来迭代,编译器就会编译这段代码。但并不是集合中的所有元素都可以强制转换为int,所以会出现一个运行异常。

      错误应该尽早的发现。在泛型类List<T>中,泛型类型T定义了允许使用的类型。有了List<int>的定义,就只能把整数类型添加到集合中。编译器就不会编译这段代码,因为Add()方法的参数无效。

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication7
    {
        class MyClass
        {
    
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var myList = new ArrayList();
                myList.Add(11);
                myList.Add("Dean McGRADY");
                myList.Add(new MyClass());
    
                foreach (int i in myList)
                {
                    Console.WriteLine(i);
                }
    
                var myList2 = new List<int>();
                myList2.Add(111);
                myList2.Add("Dean McGRADY");
                myList2.Add(new MyClass());
    
                Console.ReadKey();
            }
        }
    }

    3.二进制代码的重用

      泛型允许更好地重用二进制代码。泛型类可以定义一次,并且可以用许多不同的类型实例化。不需要像C++模版那样访问源代码。

      例如,System.Collections.Generic名称空间中的List<T>类用一个int、一个字符串和一个MyClass类型实例化:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication7
    {
        class MyClass
        {
        }
        class Program
        {
            static void Main(string[] args)
            {
                var myIntList = new List<int>();
                myIntList.Add(123);
                myIntList.Add(345);
    
                var myStringList = new List<string>();
                myStringList.Add("Dean .");
                myStringList.Add(" McGRADY");
    
                var myClassList = new List<MyClass>();
                myClassList.Add(new MyClass());
    
    
                Console.ReadKey();
            }
        }
    }

    4.代码的拓展

    5.命名约定

      如果在程序中使用泛型,在区分泛型类型和非泛型类型时就会有一定的帮助。下面是泛型类型的命名规则:

      *泛型类型的名称用字母T作为前缀。

      *如果没有特殊的要求,泛型类型允许用任意类替代,且只使用了一个泛型类型,就可以用字符T作为泛型类型的名称。

      *如果泛型类型有特定的要求(例如,它必须实现一个接口或派生自基类),或者使用了两个或多个泛型类型,就应给泛型类型使用描述性的名称。

     

      

     

     

     

     

     

     

     

     

      

    Dean二十七
  • 相关阅读:
    Maven属性
    安居客Android项目架构演进
    HttpClient 解说 (1) 基础
    linux 打包和压缩文件
    java AES-256加解密解决方法
    jdk8 分隔字符串最新方法
    springboot 过滤器,拦截器,切片的运用
    thinkphp 5.0手记
    如何使用UDP进行跨网段广播
    php multicast多播实现详解
  • 原文地址:https://www.cnblogs.com/Dean27/p/6089423.html
Copyright © 2020-2023  润新知