• 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无参构造器的类型。

  • 相关阅读:
    51Nod-1002-数塔取数问题
    Android Studio: Application Installation Failed解决方案
    1001 数组中和等于K的数对——51NOD
    51Nod-1005 大数加法
    aiml_入门学习
    vim使用进阶
    学习寒小阳的博客之统计机器翻译
    安装cywin
    TF-IDF学习
    Java文件读写操作
  • 原文地址:https://www.cnblogs.com/justinli/p/generics.html
Copyright © 2020-2023  润新知