(.NET进阶十三)泛型类/泛型方法/泛型委托/协变逆变

一、泛型类

public class GenericStack<T>
{
    private T[] stackArray;//泛型数组
    private int currentPosition;//当前位置
    private int count;//栈的数据容量

    public GenericStack(int count)
    {
        this.count = count;
        this.stackArray = new T[count];//初始化数组大小
        this.currentPosition = 0;/当前位置从0开始
    }


    //入栈
    public void Push(T item)
    {
        if(currentPosition >= count)
        {
            Console.WriteLine("当前栈空间已满!");
        }
        else
        {
            this.stackArray[currentPosition] = item;
            currentPosition++;
        }
    }

    //出栈
    public T Pop()
    {
        T result = this.stackArray[currentPosition-1];
        currentPosition--;
        return result ;
    }    

}



//调用
static void Main(string[] args)
{
    GenericStack<int> stack1 = new GenericStack<int>(5);
    stack1.Push(1);
    stack1.Push(2);
    stack1.Push(3);
    stack1.Push(4);
    stack1.Push(5);
    
    stack1.Pop();
    stack1.Pop();
    stack1.Pop();
    stack1.Pop();
    stack1.Pop();

}
  1. 泛型好处:增加类型安全,编码灵活性提高
  2. 常见泛型:泛型类 泛型方法
  3. 泛型类规范:
    1. public class 类型<T>{类的成员...}
    2. T仅为占位符,符合C#命名规则即可,表示一个通用的数据类型,在使用时用实际的类型替代
    3. 如果包含任意多个类型的参数,参数之间用逗号分隔,如GenericStack<T1,T2,T3>{...},所定义的各种类型参数,可以用做成员变量的类型,属性,方法等返回值类型及方法参数...

二、泛型约束

//default关键字使用
public class GenericClass1<T1,T2>
{
    private T1 obj1;
    
    public GenericClass1()
    {
        //泛型使用的两种错误
        //obj1 = null;
        //obj1 = new T1();//不能人为假定某种类型,因为这种类型也许没有构造方法,也许是私有的
        
        //解决方法
        obj1 = default(T1);
    }
}


//添加约束类型的泛型类
public class GenericClass2<T1,T2,T3>
        where T2:class//类型必须为引用类型
        where T3:new()//在这个类中,类型必须有一个无参构造,且必须把这个约束放在最后
                      //其他类型-->基类类型 where T2:T1{} 表示T2必须与T1类型相同或继承自T1
{
    //产品列表
    public List<T2> ProductList{get;set;}

    //发行者
    public T3 Publisher{get;set;}

    public GenericClass2()
    {
        ProductList = new List<T2>();
        Publisher = new T3();
    }

    //购买第几个产品
    public T2 BuyProduct(T1 num)
    {
        //return ProductList[num];//直接写有错误,T1不一定为int类型
        dynamic index = num;//转化为动态类型
        return ProductList[index];
    }
}

//根据泛型类要求设计参数(实际开发时自行设计)
class Course
{
    public string CourseName{get;set;}//课程名称
    public int Period{get;set;}//课程学习周期
}

class Teacher
{
    public Teacher(){}
    public string Name{get;set;}
    public int Count{get;set;}//授课数量
    
}


static void Main(string[] args)
{
    GenericClass2<int,Course,Teacher> myclass2 = new GenericClass2<int,Course,Teacher>();

    myclass2.Publisher = new Teacher{Name = "",Count = 20};
    myclass2.ProductList = new List<Course>()
    {
        new Course(){CourseName = "",Period = 6},
        new Course(){CourseName = "",Period = 7}
    }

    Course myCourse = myclass2.BuyProduct(0);
    
    Console.WriteLine("输出======");
}

三、泛型方法

//实现四则运算

static T Add1<T>(T a,T b)
{
    return a + b;//写法错误
    dynamic a1 = a;//动态类型仅在编译期间存在,运行期间会被object类型替代(编译时不考虑具体类型)
    dynamic b1 = b;
    return a1+b1;
}

static T Add2<T>(T a,T b)where T:struct
{
    dynamic a1 = a;
    dynamic b1 = b;
    return a1+b1;
}

static T Sub<T>(T a,T b)where T:struct
{
    dynamic a1 = a;
    dynamic b1 = b;
    return a1-b1;
}

static T Multiply<T>(T a,T b)where T:struct
{
    dynamic a1 = a;
    dynamic b1 = b;
    return a1*b1;
}

static T Div<T>(T a,T b)where T:struct
{
    dynamic a1 = a;
    dynamic b1 = b;
    return a1/b1;
}

//调用
static void Main(string[] args)
{
    Add1(20,30);
    Add2(10,20);
    Sub(20.5,56);
    Add2(20.5,5);
}



//实现一个数的求和
private static T Sum<T>(T a)where T : struct
{
    int sum = default(T);
    for(dynamic i=0;i<=a;i++)
    {
        sum+=i;
    }
    return sum;
}

四、泛型委托

static void Main(string[] args)
{
    MyDeletegate<int> myDeletegate1 = Add;
    MyDeletegate<double> myDeletegate2 = Sub;
    
    //调用
    myDeletegate1(10,20);
    myDeletegate2(10.5,20.7);
}

//定义泛型委托
public deletegate T MyDeletegate(T a,T b);

static int Add(int a,int b)
{
    return a+b;
}

static int Sub(double a,double b)
{
    return a-b;
}

五、Action与Func

系统提供了没有返回值和一个返回值的泛型委托

//最多可以有16个参数
public Action<int,int,int> myAction = (a1,a2,a3)=>
{
    int resule = (a1+a2)*a3
    Console.WriteLine(result);
}

///最后一个表示返回值类型
public Func<int,int,string> myFunc = (a1,a2)=>
{
    int result = a1+a2;
    return "返回值为:"+result;
}

六、协变逆变

  • 协变 out
    • 某个返回值类型可以用它的子类类型替换,则这个类型支持协变,List不支持协变
    • 应用,如:IEnumerable<父类> list= new List<子类>();
  • 逆变 in
    • 逆变是说某个《输入类型》可以用它的《父类类型替换》
    • 应用,如:Action<T>支持逆变,IEnumerable<子类> list= new List<父类>();

七、缓存

  • 总结:正常情况下,如果创建一个静态成员和静态构造方法,在第一次使用的时候会初始化,后面再次使用永远不会初始化
  •  但是如果我们使用泛型类,当我们传递不同的类型时,静态成员和静态构造,还会在第一次执行
static void Main(string[] args)
{
    CacheBaseGeneric<Student>.SaveData(new Student{name = "000"});
    CacheBaseGeneric<Student>.GetData().Name;


    CacheBaseGeneric<Teacher>.SaveData(new Student{name = "000"});
    CacheBaseGeneric<Teacher>.GetData().Name;

    
    //使用静态构造方法,不同类型进入时先进行初始化,当该类型再次进入时则不进入构造方法,直接更新缓存

    //总结:正常情况下,如果创建一个静态成员和静态构造方法,在第一次使用的时候会初始化,后面再次使用永远不会初始化
    //但是如果我们使用泛型类,当我们传递不同的类型时,静态成员和静态构造,还会在第一次执行
    
}


//基于泛型实现缓存:泛型类+静态字段+静态方法
//结论:泛型本质就是根据不同的数据类型,编译成不同的类,下面可以实现高性能不同数据类型的数据缓存
public class CacheBaseGeneric<T>where T:class,new()
{
    private static T tData = null;
    //静态构造方法
    static CacheBaseGeneric()
    {
        Console.writeLine("静态都在方法被调用,类型为:"+typeof(T));
    }

    //保存数据
    public static void SaveData(T data)
    {
        tData = data;
    }

    //获取缓存数据
    public static T GetData()
    {
        return tData;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值