第十七章 泛型

1.泛型
封装的数据不指定特定类型,而在声明或实例化期间指定类型,以最大限度的重用代码、保护类型安全。

class Queue
{
    private const int DEFAULTQUEUESIZE = 100;
    private int head=0, tail=0;
    private int elementCount = 0;
    private int[] queue;    

    public Queue()
    {
        this.queue = new int[DEFAULTQUEUESIZE];
    }

    public void Enqueue(int item)
    {
        if(elementCount == this.queue.Length)
        {
            throw new Exception("Queue full");
        }

        this.queue[head] = item;
        head++;
        head %= this.queue.Length;
        elementCount++;
        
    }

    public int Dequeue()
    {
        if(elementCount == 0)
        {
            throw new Exception("Queue empty");
        }

        int item = this.queue[tail];
        tail++;
        tail %= this.queue.Length;
        elementCount--;
        return item;
    }
}

public static void Main(string [] args)
{
    Queue queue = new Queue();
    queue.Enqueue(90);
    queue.Enqueue(10);
    queue.Enqueue(20);
    Console.WriteLine($"{queue.Dequeue()}");
    Console.WriteLine($"{queue.Dequeue()}");
    Console.WriteLine($"{queue.Dequeue()}");

    // 输出:
    //     90
    //     10
    //     20
}

a, head, tail相当于游标。向队列里添加一个元素,head游标向前移动一个格子;向队列里删除一个元素,tail游标向前移动一个格子。
b, head, tail游标都在向前移动,队列有 “先进先出,后进后出” 的特点。
c, Queue类仅支持int类型,string、long、float、自定义类型或其它类型却无法使用。使用泛型技术,设计类时不指定元素的具体类型,而使用泛型类型 T。

2.使用泛型

// 设计时,队列元素类型使用泛型类型 T
class GenericQueue<T>
{
    private const int DEFAULTQUEUESIZE = 100;
    private int head = 0, tail = 0;
    private int elementCount = 0;
    private T[] queue;

    public GenericQueue()
    {
        this.queue = new T[DEFAULTQUEUESIZE];
    }

    public void Enqueue(T item)
    {
        if (elementCount == this.queue.Length)
        {
            throw new Exception("Queue full");
        }

        this.queue[head] = item;
        head++;
        head %= this.queue.Length;
        elementCount++;
    }

    public T Dequeue()
    {
        if (elementCount == 0)
        {
            throw new Exception("Queue empty");
        }

        T item = this.queue[tail];
        tail++;
        tail %= this.queue.Length;
        elementCount--;
        return item;
    }
}

class Pizza
{
    private string _type;
    public string Type{ get => this._type;}

    public Pizza(string type)
    {
        this._type = type;
    }
}

public static void Main(string [] args)
{
    // 声明时,指定队列元素类型
    GenericQueue<string> stringQueue = new GenericQueue<string>(); 
    stringQueue.Enqueue("草莓蛋糕");
    stringQueue.Enqueue("蛋挞");
    stringQueue.Enqueue("热柠檬红茶");

    GenericQueue<long> longQueue = new GenericQueue<long>();
    longQueue.Enqueue(998);
    longQueue.Enqueue(1024);
    longQueue.Enqueue(520);

    // 自定义Pizza队列
    GenericQueue<Pizza> pizzaQueue = new GenericQueue<Pizza>(); 
    pizzaQueue.Enqueue(new Pizza("海鲜披萨"));
    pizzaQueue.Enqueue(new Pizza("培根牛肉披萨"));
    pizzaQueue.Enqueue(new Pizza("什锦水果披萨"));
}

用指定类型替换泛型参数类型T,不是简单的文本替换机制。相反,编译器会执行全面的语义替换。

GenericQueue<string> stringQueue = new GenericQueue<string>(); // string队列
GenericQueue<Pizza> pizzaQueue= new GenericQueue<Pizza>(); // 自定义Pizza队列

// string队列的方法:
public void Enqueue(string item);
public string Dequeue();

// Pizza队列的方法:
public void Enqueue(Pizza item);
public Pizza Dequeue();

每次为泛型类指定类型参数时,编译器会生成一个全新的类,它“恰好”有泛型类定义的功能。 这意味着GenericQueue<string>和GenericQueue<Pizza>是全然不同的两个类型,只是“恰好”具有相同的行为。泛型类的具体类型版本称为已构造类型(constructed type)。

posted @ 2021-03-10 15:26  葡式蛋挞  阅读(10)  评论(0)    收藏  举报