zoukankan      html  css  js  c++  java
  • c#泛型

    泛型

    一.泛型的作用

    跨类型可复用的代码:继承 和 泛型.

    继承 => 基类

    泛型 => 带有"(类型)占位符"的"模板"

    二.泛型类型

    泛型会声明类型参数-泛型的消费者需要提欧共类型参数来把占位符类型填充上.

    // 泛型类
    public class Stack<T>{
        int position;
        T[] data = new T[100];
        public void Push(T ojb) => data[poisition++] = ojb;
        public T Pop() => data[--poistion]
    }
    
    // 使用泛型
    Stack<int> stack = new Stack<int>();
    stack.Push(12);   // poistion = 1
    stack.Push(15);   // poistion = 2
    int x = stack.Pop(); // poisiton = 1 ,data[1] x = 2;
    int y = stack.Pop(); // y = 1
    
    // 推导
    public class ###{
        int position;
        int  data = new int[100];
        public void Push(int ojb) => data[poisition++] = ojb;
        public int Pop() => data[--poistion]
    }
    

    OPEN TYPE & CLOSE TYPE

    Stack Open Type(开发类型)

    Stack Close Type(封闭类型)

    在运行时,所有的泛型类型实际都是封闭的(占位符类型已经被填充了)

    var stack = new Stack<T>(); // 异常!
    
    // 下面是允许的
    public class Stack<T>{
        ...
        public Stack<T> Clone(){
            Stack<T> clone = new Stack<T>();
            ...
        }
    }
    

    泛型为什么会出现

    public class Stack{
        int position;
       	object data = new object[100];
        public void Push(object ojb) => data[poisition++] = ojb;
        public object Pop() => data[--poistion]
    }
    

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

    stack.Push("s"); // 装箱
    int i = (int)stack.Pop(); // 无法向下转换报错!!!
    

    三.泛型方法

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

    // 泛型方法
    static void Swap<T>(ref T a,ref T b){
        T temp = a;
        a = b;
        b = temp;
    }
    
    // 调用
    int a = 2;
    int b = 3;
    Swap(ref a,ref b);
    Console.WriteLine($"{a},{b}"); // a=3 b=2
    

    在泛型类型里面的方法,除非也引入了类型参数T ,否则是不会归为泛型方法的

    public class Stack<T>{
        int position;
        T[] data = new T[100];
        public void Push(T ojb) => data[poisition++] = ojb;
        public T Pop() => data[--poistion]  //这个不是泛型方法
    }
    

    只有类型和方法可以引入类型参数,属性,索引器,事件,字段,构造函数,操作符等都不可以声明类型参数,但是他们可以使用他们所在的泛型类型的类型参数.

    四.声明类型参数

    在声明class,struct,interface,delegated的时候可以引入类型参数.

    其他的例如属性,就不可以引入类型参数,但是可以使用类型参数

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

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

    class Dictionary<Tkey,Tvalue>{....};
    
    Dictionary<int,stirng> 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<>);
    Type a2 = typeof(A<,>);
    
    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) // t是引用类型那么是null t是值类型是0
        }
    }
    

    六.泛型的约束

    默认情况下,泛型的类型参数可以是任何类的类型

    如果只允许使用特定的类型参数,就可以指定约束

    where T :struct 		// 类型T必须是值类型
    where T :class 			// T必须是引用类型
    where T :IFoo 			// T必须实现接口IFoo
    where T :Foo 			// T必须派生自基类Foo
    where T :new() 			// 指定类型T必须有个一默认构造函数
    where T :T2 			// 类型T派生自泛型类型T2
    
    public class MyClass<T> where T:new(){
        ...
    }
    
    class SomeClass{}
    interface Interface1{}
    
    class GenericaClass<T,U> where T: SomeClass,Interface1  // 必须继承SomeClass 且 实现 Interface接口
        					 where U:new() // 必须有个构造函数
    {...}
    

    泛型类型的子类

    泛型class可以有子类,在子类里,可以继续让父类的类型参数保持开放

    class Stack<T>{...}
    class SpecialStack<T>:Stack<T>
    

    在子类李,也可以使用具体的类型来关闭(封闭)父类的类型参数

    class IntStack:Stack<int>{...}
    

    子类型也可以引入新的类型参数

    class List<T>{...}
    class KeyedList<T,Tkey>:List<T>
    

    自引用的泛型类型

    在封闭类型参数的时候,改类型可以把他自己作为具体的类型

    public interface IEquatable<T> {bool Equals(T obj);}
    
    public class Balloon:IEquatable<Balloon>{
        ...
        public bool Equals(Balloon b){
            if(b==null)return false;
            return true;
        }
    }
    

    静态数据

    针对每一个封闭类型,静态数据是唯一的

    class Bob<T> { public static int Count; }
    
    static class Test
    {
        public static void  set_bob()
        {
            Console.WriteLine(++Bob<int>.Count); //1
            Console.WriteLine(++Bob<int>.Count); //2
            Console.WriteLine(++Bob<string>.Count); //1
            Console.WriteLine(++Bob<object>.Count); //1
        }
    }
    

    类型参数转换

    • c#的类型操作符支持下列转换
      • 数值转换
      • 引用转换
      • 装箱拆箱转换
      • 自定义转换
    • 决定采用的是那种转换,发生在编译时,根据已知类型的操作数来决定
    public StringBuilder foo<T>(T arg){
        StringBuilder sb = arg as StringBuilder;
        .....
    }
    
    吾虽浪迹,却未迷失本心
  • 相关阅读:
    【记录】【MySQL】填充字符串函数 LPAD(str,len,padstr)
    nvm安装node和npm,个人踩坑记录
    win10系统下cmd输入一下安装的软件命令提示拒绝访问解决办法
    bootstrap大图轮播手机端不能手指滑动解决办法
    JS中函数声明与函数表达式的异同
    javaScript实现归并排序
    js插入节点appendChild和insertBefore
    JS的事件冒泡和事件捕获
    js 停止事件冒泡 阻止浏览器的默认行为
    事件绑定的几种常见方式
  • 原文地址:https://www.cnblogs.com/lddragon1/p/15545570.html
Copyright © 2011-2022 走看看