美文网首页
C# 泛型简介 01

C# 泛型简介 01

作者: JeetChan | 来源:发表于2019-08-18 14:36 被阅读0次

    声明

    本文内容来自微软 MVP solenovex 的视频教程——真会C#? - 第3章 泛型简介(完结),大致和第 1 课—— 3.9 泛型为什么存在、类型参数、默认值等 对应。可在 GitHub 中查看 C# 视频教程的配套PPT

    本文主要包括以下内容:

    1. 泛型类型
    2. 为什么泛型会出现
    3. 泛型方法
    4. 声明类型参数
    5. typeof 与未绑定的泛型类型
    6. 泛型的默认值

    泛型

    C# 语言和公共语言运行时 (CLR) 的 2.0 版本中添加了泛型。 泛型将类型参数的概念引入 .NET Framework,这样就可以设计具有以下特征的类和方法:在客户端代码声明并初始化这些类和方法之前,这些类和方法会延迟指定一个或多个类型。 例如,通过使用泛型类型参数 T,可以编写其他客户端代码能够使用的单个类,而不会产生运行时转换或装箱操作的成本或风险。

    C# 泛型和 C++ 模板是类似的概念,但它们的工作方式不同。

    泛型类型

    泛型会声明类型参数 – 泛型的消费者需要提供类型参数(argument)来把占位符类型填充上。

    public class Stack<T>
    {
        int position;
        T[] data = new T[100];
        public void Push (T obj) => data[position++] = obj;
        public T Pop() => data[--position];
    }
    
    var stack = new Stack<int>();
    stack.Push (5);
    stack.Push (10);
    int x = stack.Pop(); // x is 10
    int y = stack.Pop(); // y is 5
    
    public class ###
    {
        int position;
        int[] data = new int[100];
        public void Push (int obj) => data[position++] = obj;
        public int Pop() => data[--position];
    }
    

    Stack<T> Open Type(开放类型),Stack<int> Closed Type(封闭类型),在运行时,所有的泛型类型实例都是封闭的(占位符类型已被填充了)。

    var stack = new Stack<T>(); // Illegal: What is T?
    
    public class Stack<T>
    {
        ...
        public Stack<T> Clone()
        {
            Stack<T> clone = new Stack<T>(); // Legal
            ...
        }
    }
    

    为什么泛型会出现

    public class ObjectStack
    {
        int position;
        object[] data = new object[10];
        public void Push (object obj) => data[position++] = obj;
        public object Pop() => data[--position];
    }
    

    需要装箱和向下转换,这种转换在编译时无法进行检查。

    // Suppose we just want to store integers here:
    ObjectStack stack = new ObjectStack();
    stack.Push ("s"); // Wrong type, but no error!
    int i = (int)stack.Pop(); // Downcast - runtime error
    

    泛型方法

    泛型方法在方法的签名内也可以声明类型参数。

    static void Swap<T> (ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }
    
    int x = 5;
    int y = 10;
    Swap (ref x, ref y);
    
    Swap<int> (ref x, ref y);
    

    在泛型类型里面的方法,除非也引入了类型参数(type parameters),否则是不会归为泛型方法的。只有类型和方法可以引入类型参数,属性、索引器、事件、字段、构造函数、操作符等都不可以声明类型参数。但是他们可以使用他们所在的泛型类型的类型参数。

    public T this [int index] => data [index];
    
    public Stack<T>() { } // Illegal
    

    声明类型参数

    在声明 class、struct、interface、delegate 的时候可以引入类型参数(Type parameters)。其它的例如属性,就不可以引入类型参数,但是可以使用类型参数。

    public struct Nullable<T>
    {
        public T Value { get; }
    }
    

    泛型类型/泛型方法可以有多个类型参数:

    class Dictionary<TKey, TValue> {...}
    
    Dictionary<int,string> myDic = new Dictionary<int,string>();
    
    var myDic = new Dictionary<int,string>();
    

    声明泛型类型

    泛型类型/泛型方法的名称可以被重载,条件是参数类型的个数不同:

    class A {}
    class A<T> {}
    class A<T1,T2> {}
    

    按约定,泛型类型/泛型方法如果只有一个类型参数,那么就叫 T。当使用多个类型参数的时候,每个类型参数都使用T作为前缀,随后跟着具有描述性的一个名字。

    typeof 与未绑定的泛型类型

    开放的泛型类型在编译后就变成了封闭的泛型类型。但是如果作为Type对象,那么未绑定的泛型类型在运行时是可以存在的。(只能通过 typeof 操作符来实现)

    class A<T> {}
    class A<T1,T2> {}
    ...
    Type a1 = typeof (A<>); // Unbound type (notice no type arguments).
    Type a2 = typeof (A<,>); // Use commas to indicate multiple type args.
    
    Type a3 = typeof (A<int,int>);
    
    class B<T> { void X() { Type t = typeof (T); } }
    

    泛型的默认值

    使用 default 关键字来获取泛型类型参数的默认值。

    static void Zap<T> (T[] array)
    {
        for (int i = 0; i < array.Length; i++)
            array[i] = default(T);
    }
    
    Generics

    参考

    Generics (C# Programming Guide)
    Generic Methods (C# Programming Guide)
    Generic Classes (C# Programming Guide)

    相关文章

      网友评论

          本文标题:C# 泛型简介 01

          本文链接:https://www.haomeiwen.com/subject/qimrsctx.html