C# 泛型编程

          感觉对于编程这个工作,我开始一直是这样认为的,还是我们现在好。比如说语言发展了,发展成更容易理解和编程了;工具也发展了,编程的时候更方便了,比如说现在的智能提示。

          但是这样理解好像有点片面了,如果不理解一个技术的发展历史就很难真正理解它。C# 泛型编程是2.0就有的,可是自己的理解还不够,特此好好总结一下。

C# 泛型及机制

         C#泛型演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Stack<int> test = new Stack<int>();
            test.Push(10);
            Console.WriteLine(test.GetResult());
            Console.Read();
        }
    }

    class Stack<T> 
    {
        private T[] store;
        private int size;

        public Stack()
        {
            store = new T[10];
            size = 0;
        }

        public void Push(T x)
        {
            store[size++] = x;
        }

        public T Pop()
        {
            return store[--size];
        }

        public string GetResult()
        {
            return store[--size].ToString();
        }
    }
}


        C#泛型简介

所谓泛型,即通过参数化类型来实现在同一份代码上的操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。

C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束

        C#泛型机制简介

C#泛型能力由CLR在运行时支持,区别于C++ 的编译时模板机制,和Java的编译时“ 搽拭法” 。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。

C#泛型代码在被编译为IL 代码和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL 指令支持泛型操作。而真正的泛型实例化工作以“on-demand” 的方式,发生在JIT编译时。

       C#泛型编译机制

第一轮编译时,编译器只为Stack<T>类型产生“ 泛型版” 的IL 代码与元数据——并不进行泛型类型的实例化,T在中间只充当占位符

JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int替换“ 泛型版”IL代码与元数据中的T——进行泛型类型的实例化。

CLR 为所有类型参数为“ 引用类型” 的泛型类型产生同一份代码;但如果类型参数为“ 值类型” ,对每一个不同的“ 值类型” ,CLR将为其产生一份独立的代码

        C#泛型的几个特点

如果实例化泛型类型的参数相同,那么JIT编译器会重复使用该类型,因此C#的动态泛型能力避免了C++ 静态模板可能导致的代码膨胀的问题。
•C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。
•C#的泛型采用“ 基类,  接口,  构造器,  值类型/引用类型” 的约束方式来实现对类型参数的 “ 显式约束” ,提高了类型安全的同时,也丧失了C++ 模板基于“ 签名” 的隐式约束所具有的高灵活性。

泛型类型

         C#泛型类与结构

class C<U, V> { }   //合法
    class D : C<string, int> { }    //合法
    class E<U, V> : C<U, V> { }     //合法
    class F<U, V> : C<string, int> { }  //合法
    //非法
    //class G : C<U, V> { };


       C#除可单独声明泛型类型(包括类与结构)外,也可在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型参数要么已实例化,要么来源于子类(同样是泛型类型)声明的类型参数。

             泛型类型的成员

 class D<V>
    {
        
    }

    class C<V>
    {
        public V fi1;   //声明字段
        public D<V> f2;  //作为其它泛型类型的参数
        public C(V x)   
        {
            this.fi1 = x;
        }
    }


       泛型类型的成员可以使用泛型类型声明中的类型参数。但类型参数如果没有任何约束,则只能在该类型上使用从System.Object继承的公有成员。

       泛型接口

 interface IList<T>
    {
        T[] GetElements();
    }
    interface IDictionary<K, V>
    {
        void Add(K key, V value);
    }

    class List<T> : IList<T>,IDictionary<int,T>
    {

        public void Add(int key, T value)
        {
            throw new NotImplementedException();
        }

        public T[] GetElements()
        {
            throw new NotImplementedException();
        }
    }


泛型接口的类型参数要么已实例化,  要么来源于实现类声明的类型参数。

         泛型委托

delegate bool Predicate<T>(T value);
    class X
    {
        static bool F(int i){ return true;}
        static bool G(string s) { return false; }

        static void Main()
        {
            Predicate<string> P2 = G;
            Predicate<int> p1 = new Predicate<int>(F);
        }
    }


泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束。

       泛型方法

         泛型方法简介

•C#泛型机制只支持 “在方法声明上包含类型参数”——即泛型方法
•C#泛型机制不支持在除方法外的其他成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数
• 泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中

        泛型方法的声明与调用

 public class Finder
    {
        //泛型方法的声明
        public static int Find<T>(T[] items, T item)
        {
            for (int i = 0; i < items.Length; i++)
            {
                if (items[i].Equals(item))
                {
                    return i;
                }
            }
            return -1;
        }

        //泛型方法的调用
        int i = Finder.Find<int>(new int[] { 1,3,4,5,6}, 6);
    }


     泛型方法的重载

 public class MyClass
    {
        void F1<T>(T[] a,int i);
        void F1<U>(U[] a, int i);   //不可以构成重载方法

        void F2<T>(int x);
        void F2(int x);     //可以构成重载方法

        void F3<T>(T t) where T : A;
        void F3<T>(T t) where T : B;
    }

    class A{}
    class B { }


     泛型方法的重写

 abstract class Base
    {
        public abstract T F<T, U>(T t, U u) where U : T;
        public abstract T G<T>(T t) where T : IComparable;
    }

    class Derived : Base
    {
        // 合法的重写,约束被默认继承
        public override T F<T, U>(T t, U u)
        {
            throw new NotImplementedException();
        }

        // 非法的重写,指定任何约束都是多余的
        public override T G<T>(T t) where T:IComparable
        {
            throw new NotImplementedException();
        }
    }

       泛型约束

          泛型约束简介

•C#泛型要求对“ 所有泛型类型或泛型方法的类型参数” 的任何假定,都要基于“ 显式的约束” ,以维护C#所要求的类型安全。
•“显式约束” 由where 子句表达,可以指定“ 基类约束” ,“ 接口约束” ,“ 构造器约束” ,“ 值类型/引用类型约束” 共四种约束。
•“显式约束” 并非必须,如果没有指定“ 显式约束” ,泛型类型参数将只能访问System.Object类型中的公有方法。

          基类约束

class A{ public void F1(){} }
    class B { public void F2(){} }
    class C<S,T>
        where S:A   //S继承自A
        where T:B   //T继承自B
    {
        //可以在类型为S的变量上调用F1
        //可以在类型为T的变量上调用F2
        
    }


        接口约束

//接口约束 
    interface IPrintable{void Print();}
    interface IComparable<T>{int CompareTo(T v);}
    interface IKeyProvider<T>{T GetKey();}

    class Dictionary<K,V>
        where K:IComparable<K>
        where V:IPrintable,IKeyProvider<K>
    {
        //  可以在类型为K的变量上调用CompareTo,
        //  可以在类型为V的变量上调用Print和GetKey
    }


      构造器约束

 class A{public A(){}}
    class B{public B(int i){}}

    class W<T> where T:new()
    {
        
    }
   public class test
   {
       W<A> c=new W<A>();   //可以A有无参构造函数
       W<B> c=new W<B>();   //错误,B没有无参构造器
   }


     值类型/引用类型约束


       

         

发布了138 篇原创文章 · 获赞 11 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/yjjm1990/article/details/9498923