c# 泛型总结

一、泛型概述:

泛型是C# 2.0引入的新特性,泛型为开发者提供了类型的参数化的形式,他带来的最大的好处之一是代码的复用。他是通过运行时类型绑定来实现代码的复用,或者说算法的复用。其次,泛型为我们带来的另一个好处是性能的提升,再次,它提供了编译时类型的安全检查,为程序员减轻了负担。下面将分别通过例子来就这三个方面来做个介绍。

一、算法的复用。

下面我将举一个简单的例子,实现了一个简单的List容器,提供Add元素的方法。

namespace GenericTest
{
    public class SimpleList<TIn>
    {
        private static TIn[] _element;
        private const int DefaultSize = 5;
        private int _currentIndex = -1;
        private int _allocSize;
        private int _length;
        public SimpleList()
        {
            _element = new TIn[DefaultSize];
            _allocSize = DefaultSize;

        }

        public TIn this[int index] { get { return _element[index]; } set { _element[index] = value; } }
        public void Add(TIn value)
        {

            _currentIndex++;
            if (_currentIndex >= DefaultSize)
            {
                _allocSize = _allocSize * 2;
                TIn[] tmp = _element;
                _element = new TIn[_allocSize];
                tmp.CopyTo(_element, 0);

            }
            _element[_currentIndex] = value;
            _length++;
        }
        public int Length { get { return _length; }}

    }
    class Program
    {
        static void Main(string[] args)
        {

            SimpleList<int> a = new SimpleList<int>();
            a.Add(1);
            a.Add(2);
            a.Add(3);

            for (int i = 0; i < a.Length; i++)
            {
                Console.WriteLine(a[i]);
            }
            SimpleList<float> a1 = new SimpleList<float>();
            a1.Add(2.3f);
            for (int i = 0; i < a1.Length; i++)
            {
                Console.WriteLine(a[i]);
            }

        }
    }
}

从代码中我们可以看出我们定义的SimpleList类型Add方法带有泛型参数,表明其可以接受任何类型的元素作为参数,当没有泛型时,我们添加元素时,需要为每种类型都定义一个方法或者定义一个接收object类型参数的方法,运行时执行装箱拆箱操作,进而影响程序的性能,以及不能提供编译时类型的安全检查。通过上面的例子我们可以看出泛型为我们带来的是算法的复用,SimpList这个简单的容器的Add方法能够运用在任何类型的元素的添加上。

二、编译时类型的安全检查。

我们在简单定义一个Student类:

class Student
{
public string Name { get; set; }
public int Age { get; set; }
}

在实例化一个Student of SimpleList 的实例 :SimpleList<Student> st = new SimpleList<Student>(); 当我们向其中添加int元素时 st.Add(2),编译器报错,提示参数类型int不能赋值给参数类型Student,这便是泛型提供的编译时类型检查的好处,我们不能随便向其中添加元素。

三、性能的提升。

下面性能的提升,我们通过c#类库提供的两个容器来说明问题,一个是List,是System.Collections.Generic提供的泛型类型,一个是ArrayList,是System.Collections提供的非泛型类型。分别对值类型和引用类型进行测试:

namespace ListBenchmark
{
    class Program
    {
        static void Main(string[] args)
        {
            ValueTypePerfTest();
            ReferencePerfTest();
        }

        private static void ValueTypePerfTest()
        {
            int count = 10000000;
            using (new OperationTimer("List<Int32>"))
            {
                List<Int32> l = new List<Int32>();
                for (int i = 0; i < count; i++)
                {
                    l.Add(i);       //未装箱
                    Int32 x = l[i]; //未拆箱
                }
                l = null;  //确保垃圾收集器回收

            }

            using (new OperationTimer("ArrayList<Int32>"))
            {
                ArrayList a = new ArrayList();

                for (int i = 0; i < count; i++)
                {
                    a.Add(i);       //装箱
                    Int32 x = (int)a[i];//拆箱
                }
                a = null;//确保垃圾收集器回收

            }

        }

        private static void ReferencePerfTest()
        {
            const int count = 10000000;

            using (new OperationTimer("List<string>"))
            {
                List<string> l = new List<string>();
                for (int i = 0; i < count; i++)
                {
                    l.Add("X"); //引用copy
                    string x = l[i]; // 引用copy
                }
                l = null;

            }

            using (new OperationTimer("ArrayList<string>"))
            {
                ArrayList a = new ArrayList();
                for (int i = 0; i < count; i++)
                {
                    a.Add("X"); //引用copy
                    string x = (String)a[i]; //cast check & 引用copy
                }
                a = null;

            }

        }

    }

    internal sealed class OperationTimer : IDisposable
    {
        private Stopwatch m_stopwatch;
        private string m_text;
        private int m_collectionCount;

        public OperationTimer(string text)
        {
            PrepareForOperation();
            m_text = text;
            m_collectionCount = GC.CollectionCount(0);
            m_stopwatch = Stopwatch.StartNew();

        }

        private static void PrepareForOperation()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
        public void Dispose()
        {
            Console.WriteLine("{0}(GCs={1,3}) {2}",(m_stopwatch.Elapsed),GC.CollectionCount(0)- m_collectionCount,m_text);
        }
    }
}

程序运行结果:从中可以看出对于值类型,List比ArrayList有很大的性能的提升,主要是List添加元素时不需要进行boxing,获取元素不需要unboxing,同时可以正是由于ArrayList的装箱拆箱操作导致垃圾收集次数比较多。对于引用类型则执行时间相差无几,只是做引用拷贝及获取元素时的类型转换检查。

泛型类型的好处介绍到这,下面简单的介绍一下泛型类型参数的约束。

四、泛型的类型参数约束:

泛型类型参数的约束规定了参数的编译时类型的限制。主要有引用类型约束,引用类型的约束不能使用一下之一:Object,Array,Delegate,MulticastDelegate ,ValueType,Enum,System.Void。例如如下泛型约束:

internal sealed class PrimaryConstratinOfStream<T> where T: Stream{},其中where为类型约束关键词,该类型约束表明了使用PrimaryConstratinOfStream必须指定参数类型T为Stream类型或者派生自Stream类型,如FileStream;其中引用类型约束的两个特殊的约束分别是class和struct,where T:class,表示T必须是引用类型,而where T:struct则表示T必须是值类型。

其次,还有一种泛型类型约束的是接口类型,当指定了接口的约束,在使用对象时对于指定类型参数必须实现该接口。最后一种约束是构造器约束,如:

class ConstructorConstraint<T> where T: new(){},它告诉编译器T必须是带有一个public无参构造器的类型。

时间: 2024-08-23 14:24:40

c# 泛型总结的相关文章

.NET编程01(泛型)

一:Object 类型:一切类型的父类,通过继承,子类拥有父类一切属性和行为:任何父类出现的地方,都可以用子类来代替: 用一个方法来完成多个方法做的事 /// <summary>    /// 普通方法类    /// </summary>    public class CommonMethod    {        /// <summary>        /// 打印个int值        /// </summary>        /// <

c#系统泛型委托

Action<T> 无返回值的系统泛型委托 namespace ConsoleApp1 { public class UserInfo { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } class Program { private static List<UserInfo> getInit() { return new List<User

泛型2

万用字符(wildcard) 以动物Animal类为例,怎样才能创建出一种ArrayList<?>里面既可以保存ArrayList<Dog>,又可以保存ArrayList<Cat>? public void takeAnimals(ArrayList<? extends Animal> animals){  //泛型中extends同时代表继承和实现. for(Animal a : animals){ a.eat(); } } 我们可以这样调用该函数: Ar

通过反射了解集合泛型的本质

通过反射了解集合泛型的本质 import java.lang.reflect.Method; import java.util.ArrayList; /** * 通过反射了解集合泛型的本质 * @author shm * */ public class MethodDemo02 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("hello"); list.add(

构造方法中使用泛型

------------siwuxie095 构造方法中使用泛型: 构造方法可以为类中的属性初始化,如果类中的属性通过泛型指定,而又需要 通过构造方法设置属性内容的时候,构造方法的定义与之前并无不同,不需要 像声明类那样指定泛型 package com.siwuxie095.generic; class Context<T>{ private T value; public Context(T value) { this.value=value; } public T getValue() {

泛型委托当参数传递

假如有一个Person类: public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Title { get; set; } } 执行一个方法: /// <summary> /// 传递一个泛型委托方法 /// </summary> /// <param name="acti

类库,委托,is和as运算符,泛型集合

类库:其实就是一堆类文件,只不过用户看不到这些类的源代码,保密性好. 优点:保密性好缺点:如果这个方法不好用,使用者无法自己去更改它. 类文件是.cs    类库是.dll 新建项目为类库,在debug文件夹下找到dll文件 委托:委托可以理解为:函数的指针 关键词:delegate 声明委托类型:public delegate int FirstDel(int a, int b); FirstDel不是类,是委托变量,不能实例化(不能new), 创建委托变量:FirstDel 名字 = 与这个

泛型委托

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 泛型委托 { public delegate int DelCompare<T>(T t1, T t2); // public delegate int DelCompare(object o1, object o2); class Progra

java 16-8 泛型高级之通配符

泛型高级(通配符) ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了 ? extends E:向下限定,E及其子类 ? super E:向上限定,E极其父类 1 import java.util.ArrayList; 2 import java.util.Collection; 3 public class GenericDemo { 4 public static void main(String[] args) { 5 // 泛型如果明确的写的时候,前后必须一致 6 C

蓝鸥Unity开发基础二——课时21 泛型

本节课我们来学习C#中的泛型,泛型是一个特殊的类型,它可以最大限度的重用我们的代码! 推荐视频讲师博客:http://11165165.blog.51cto.com/ 使用泛型能够最大限度的重用代码,保护类型安全,提高性能 泛型成员因为类型的不确定性,不能使用算术运算符,比较运算符 类型参数可以有多个,可以是编译器能够识别的任何类型 类型参数的名字不能够随便起,不能重名 一.数组类Array using System; namespace Lesson_21{    //数组类Array