首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 泛型約束核心教學(一):IComparable 約束與可排序單鏈表從零構建

     編輯:關於C語言

為什麼需要約束?

泛型類別操作未知型別 T 時,若需呼叫 T 的特定方法(如比較),必須在編譯期保證 T 擁有該能力。where T : IComparable<T> 即為此契約。

完整實作程式碼

Employee:可比較的資料類別


public class Employee : IComparable
{
    private string _name;
    public Employee(string name) => _name = name;

    public int CompareTo(Employee other) => _name.CompareTo(other._name);
    public bool Equals(Employee other) => _name == other._name;
    public override string ToString() => _name;
}

Node:雙向鏈表節點,雙重約束


public class Node : IComparable> where T : IComparable
{
    private T _data;
    private Node _next;
    private Node _prev;

    public Node(T data) => _data = data;

    public T Data => _data;
    public Node Next => _next;

    public int CompareTo(Node other) => _data.CompareTo(other._data);

    public bool Equals(Node other) => _data.Equals(other._data);

    // 遞迴插入:維持升序
    public Node Add(Node newNode)
    {
        if (this.CompareTo(newNode) > 0) // 新節點較小 → 插入前方
        {
            newNode._next = this;
            if (this._prev != null)
            {
                this._prev._next = newNode;
                newNode._prev = this._prev;
            }
            this._prev = newNode;
            return newNode; // 成為新頭節點
        }
        else // 插入後方
        {
            if (this._next != null)
                this._next.Add(newNode);
            else
            {
                this._next = newNode;
                newNode._prev = this;
            }
            return this; // 維持原頭節點
        }
    }

    public override string ToString()
    {
        string output = _data.ToString();
        if (_next != null) output += ", " + _next.ToString();
        return output;
    }
}

LinkedList:約束傳遞與索引器


public class LinkedList where T : IComparable
{
    private Node _head;

    public T this[int index]
    {
        get
        {
            int ctr = 0;
            var node = _head;
            while (node != null && ctr <= index)
            {
                if (ctr == index) return node.Data;
                node = node.Next;
                ctr++;
            }
            throw new ArgumentOutOfRangeException();
        }
    }

    public void Add(T data)
    {
        _head = _head == null ? new Node(data) : _head.Add(new Node(data));
    }

    public override string ToString() => _head?.ToString() ?? string.Empty;
}

測試程式


public class Test
{
    public void Run()
    {
        var intList = new LinkedList();
        var rand = new Random();
        Console.Write("Adding: ");
        for (int i = 0; i < 10; i++)
        {
            int n = rand.Next(10);
            Console.Write($"{n} ");
            intList.Add(n);
        }

        var empList = new LinkedList();
        empList.Add(new Employee("John"));
        empList.Add(new Employee("Paul"));
        empList.Add(new Employee("George"));
        empList.Add(new Employee("Ringo"));

        Console.WriteLine("\nIntegers: " + intList);
        Console.WriteLine("Employees: " + empList);
    }
}

關鍵設計解析

約束傳遞鏈


LinkedList where T : IComparable
    → Node where T : IComparable
        → T.CompareTo(T)  // 編譯期保證合法

遞迴插入的頭節點維護

  • 插入前方時回傳新節點,呼叫端 _head = _head.Add(...) 更新頭指標
  • 插入後方時回傳原節點,頭指標不變

索引器 O(n) 特性

鏈表不支援隨機存取,索引器需從頭遍歷,適合頻繁插入刪除、稀少隨機存取場景。

約束的分類與語法

約束類型語法適用場景
介面約束where T : IInterface需要特定行為契約
基類約束where T : BaseClass需要共享基類功能
建構式約束where T : new()需無參數建構實例
實值型別約束where T : struct堆疊分配、免 GC
參考型別約束where T : class可為 null、參考語意
非受控型別約束where T : unmanaged可用 stackalloc、指標運算

常見錯誤與修正


// 錯誤:非泛型 IComparable 無法提供型別安全
public class BadNode : IComparable> where T : IComparable

// 正確:泛型 IComparable 保證 CompareTo 參數型別正確
public class GoodNode : IComparable> where T : IComparable
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved