第壹章第15节 C#和TS语言对比-泛型

C#提供了泛型的完整支持,不仅在编译时,运行时仍然保留泛型的类型信息,同时提供了更加丰富的泛型约束和更加全面的协变逆变支持。TS的泛型,在语法表现形式上,和C#差不多,但本质上两者是不一样的。TS的泛型,和Java一样,使用类型擦除机制,泛型只存在于编译时,在运行时,泛型的类型信息会被移除。

一、泛型究竟有啥意义

1.1 泛型应用的经典案例

正常情况下,我们还没真正懂泛型的时候,已经大量使用到(注意,是使用,不是定义),比如List、Func、Repository<MyClass,long>等等。下面是一个经典例子,大家参考一下,我觉得要到自己去封装一个泛型仓储时,才会真正领会到泛型的强大,这部分内容要到AspNetCore一章。下例中,假设我们需要创建一个数据存储类,它可以存储和检索任何类型的数据,我们使用泛型来实现这个需求。

//1、C#实现==========================================================================
//定义类时,使用泛型(类型的占位符)
public class Storage<T>
{
   
   
    //存储数据的字段_data
    private T _data;
    //保存数据的方法
    public void Store(T data)
    {
   
   
        _data = data;
        Console.WriteLine("Data stored: " + data);
    }
    //获取数据的方法
    public T Retrieve()
    {
   
   
        Console.WriteLine("Data retrieved: " + _data);
        return _data;
    }
}
//实例化类时,确定泛型的具体类型
public class Program
{
   
   
    public static void Main()
    {
   
   
        //保存和读取整数类型数据
        Storage<int> intStorage = new Storage<int>();
        intStorage.Store(42);
        int retrievedInt = intStorage.Retrieve();
        //保存和读取字符串类型数据
        Storage<string> stringStorage = new Storage<string>();
        stringStorage.Store("Hello, World!");
        string retrievedString = stringStorage.Retrieve();
    }
}


//2、TS实现==========================================================================
class Storage<T> {
   
   
    //存储数据的字段_data
    private data: T;
    //保存数据的方法
    store(data: T): void {
   
   
        this.data = data;
        console.log("Data stored: " + data);
    }
    //读取数据的方法
    retrieve(): T {
   
   
        console.log("Data retrieved: " + this.data);
        return this.data;
    }
}
//保存和读取整数类型数据
const intStorage = new Storage<number>();
intStorage.store(42);
const retrievedInt = intStorage.retrieve();
//保存和读取字符串类型数据
const stringStorage = new Storage<string>();
stringStorage.store("Hello, World!");
const retrievedString = stringStorage.retrieve();

1.2 泛型的作用总结

  • 上例中我们进行了整数和字符串的保存和读取,实际上可以进行任意类型数据的保存和读取。如果没有泛型,我们需要定义StorageInt、StorageString等等超多个class,如果方法逻辑变了,还得一个个修改。减少代码重复、增强类型安全,这是泛型的最大意义,即使像TS、Java这样的类型擦除机制的泛型,都能实现。
  • 实际开发中,除了大量使用到框架为我们定义好的泛型类型,比如语言框架提供的List、Array、Action、Func等,也有系统框架为提供的,比如ABP的Repository、Vue的defineProps()等等。我们自己也时常会定义自己的泛型,特别是在有数据传输场景,由于无法提前获知数据的具体类型,通常需要封装一个通用方法,比如使用TS开发前端应用时,一般需要使用泛型二次封装一下axios。
  • 有人说,泛型是类型的参数,非常对,但不好理解。我觉得,说泛型是类型的占位符,会更易理解。比如上例中的_data字段,我们定义时,无法确定具体类型,那就先用一个符号代替,用的时候,再确定具体类型。这个占位符可以是本例的T,也可以是V,也可以是TValue,它只是一个占位的符号。
  • 补充说一下类型擦除:Java和TS的泛型,都使用了类型擦除机制,泛型只存在于编译时,运行时泛型会被移除。这会造成什么影响呢?举个例子,由于泛型类型被移除,List和List,在运行时,通过反射获取类型时,结果是一样的,无法区分,这会在一定程度上限制反射的能力,同时也增加了一些不可预测的运行时类型错误的风险。总之,C#的泛型肯定是可以将Java按在地上摩擦的,除此之后,还有许多语言特性,一样有此能力,比如反射、LINQ、属性、事件,async/await…

二、泛型类、接口和方法

2.1 泛型类的定义和使用

2.1.1 C#中定义和使用泛型类
//定义泛型类
public class GenericClass<T>
{
   
   
    private T _value; //字段类型

    public GenericClass(T value) //构造方法的参数
    {
   
   
        _value = value;
    }

    public T 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值