Unity C# 爆破计划(十二):泛型

15 篇文章 1 订阅


十二、泛型

Covers:泛型

概念

考虑在算法一节接触过的“交换变量内容”,我们可以这样写:

static void Swap(ref int a, ref int b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

Swap 函数通过引用传参,可以操作调用方传入的变量,将两个整型变量的内容互换。现在问题来了,我们又想写一个函数来交换两个浮点型变量的内容:

static void Swap(ref double a, ref double b)
{
    double tmp = a;
    a = b;
    b = tmp;
}

我们重载了 Swap,做了一个接受两个浮点型的版本。现在我们还想交换 decimal、bool 等等数据类型的内容……我们真的要重载那么多 Swap 吗??

泛型 了解一下:

static void Swap<T>(ref T a, ref T b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

这个方法看起来有点奇怪?在函数名右面增加了一个 <T>,这就是 C# 中引入泛型的语法,它表示在 Swap 这个方法的作用域(花括号)内,我们用 类型参数 T(也可以用别的名称,T 只是约定俗成)来指代“任何类型”。上面这段代码与更上面的两段非常相似,只有类型用 T 代替了;如果用任何实际类型替换 T,含泛型的代码就可以直接变换为适应于那种类型的等效代码,换言之,泛型代码就像一个代码的“模板”,它规划了如何用实际类型替换其中的 T,从而生成实际代码,谁替我们完成这个替换工作?编译器。

泛型编程基础

泛型是 静态多态 的实现手段之一(一个泛类型 T,当赋以不同实际类型时,表现出不同的功能和性质),只有静态类型(强类型)语言才有泛型编程。它允许我们超越类型的概念,让类型变得通透,最大限度地重用代码,并更多地从智能 IDE/编译器中获得辅助。

C++ 的泛型是通过模板实现的,在漫长的 C++ 编程史中,才华横溢的程序员们发展出了灿烂的、精巧的、极尽复杂的、巴洛克式的泛型技巧,包括但不限于偏特化、萃取、模板元等,模板及其艺术般的应用是 C++ 继指针之后实至名归的另一瑰宝,原生的 C++ 标准模板库更是将泛型技术发挥到了极致,一切均用泛型编写。

咳咳,言归正传,我们的目的是简单认识泛型,并且通过了解泛型为后续学习 .NET 标准容器提供基础知识。

类、接口、方法都可以用泛型定义;泛型具有作用域的覆盖性,即 如果一个类具有泛型,那么其所有成员就都具有泛型(不需要也不允许再次声明 T)。

下面是一个泛型类的例子:

using System;

namespace Learning
{
    class MyArray<T>
    {
        T[] _array;

        public MyArray(int capacity = 0xffff)
        {
            _array = new T[capacity];
        }

        public T Get(int pos)
        {
            return _array[pos];
        }

        public void Set(int pos, T data)
        {
            _array[pos] = data;
        }
    }
}

这里我们直接泛型定义了 class MyArray,类型参数 T,那么在整个 class 的作用域内,所有成员就都可以使用 T,而不需要再次定义 T。

泛型代码在编译时必须完成类型推导才有实际意义,因此我们需要为类型参数绑定实际类型,有两种方式:

  1. 显式绑定,在调用处,直接在类名或方法名后面加上 用尖括号括起来的实际类型 <TYPE>,就将实际类型 TYPE 绑定到了类型参数 T 上;
  2. 隐式绑定,在调用处不写实际类型,就像使用普通方法一样。只有泛型方法才能隐式绑定实际类型,因为 实际类型可以从填入的参数推断,这称为 (静态)类型推导

我们为上面的 MyArray 和更前面的泛型 Swap 写一些测试代码:

class Program
{
    static void Main()
    {
        var array = new MyArray<double>();
        array.Set(0, 1.414);
        array.Set(1, 0.618);

        double a = array.Get(0), b = array.Get(1);
        Swap(ref a, ref b);
        Console.WriteLine("{0}, {1}", a, b);
    }
}

这里我们显式为类 MyArray 绑定了实际类型 double;调用 Swap 时,由于已经能从 a 和 b 的类型推断出 Swap 的实际类型,故不需要显式给出。


T.B.C.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值