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

.NET 泛型進階:自訂泛型類別、約束與預設值完整解析

     編輯:ASP.NET 基礎

前言:泛型不只是 List<T>

.NET 基礎類庫大量使用泛型:List<T>、Dictionary<TKey, TValue>、Nullable<T>(即 T?)。但許多開發者僅停留在「使用」層面,未嘗試「定義」屬於自己的泛型。本文從語法基礎、default 關鍵字、型別約束、實戰範例(農場動物體系)四個維度,帶您掌握自訂泛型的核心技能。

1. 定義泛型類別語法

// 單一型別參數
public class MyGenericClass<T> { }

// 多型別參數
public class MyGenericClass<T1, T2, T3>
{
    private T1 _t1Object;

    public MyGenericClass(T1 item) => _t1Object = item;

    public T1 T1Object => _t1Object;
}

型別參數命名慣例:單字母 T、TKey、TValue 或描述性名稱 TEntity、TDto。

2. 陷阱:無法直接 new T()

// 編譯錯誤:不知道 T 是否有公用無參建構函式
public MyGenericClass() { _t1Object = new T1(); }

3. 解決方案:default 關鍵字

public MyGenericClass() { _t1Object = default(T1); }
// 值型別 → 0/false/結構體零值;參考型別 → null

4. 型別約束

透過 where 限制型別參數,獲得編譯期型別安全與 IntelliSense 提示:

約束語法含義
where T : struct值型別(排除 Nullable)
where T : class參考型別
where T : new()有公用無參建構函式
where T : BaseClass繼承自 BaseClass
where T : IInterface實作介面
where T : unmanaged非受控型別 (C# 7.3+)
where T : notnull非可為 null 型別 (C# 8+)
where T : default覆寫預設約束 (C# 9+)

多型別參數各自約束:class MyClass<T1, T2> where T1 : class where T2 : new()

5. 實戰範例:農場體系

領域模型


public abstract class Animal
{
    public string Name { get; set; }
    public Animal() => Name = "The animal with no name";
    public Animal(string name) => Name = name;
    public void Feed() => Console.WriteLine($"{Name} has been fed.");
    public abstract void MakeANoise();
}

public class Cow : Animal
{
    public Cow(string name) : base(name) { }
    public override void MakeANoise() => Console.WriteLine($"{Name} says 'moo!'");
}

public class Chicken : Animal
{
    public Chicken(string name) : base(name) { }
    public override void MakeANoise() => Console.WriteLine($"{Name} says 'cluck'");
}

public class SuperCow : Cow
{
    public SuperCow(string name) : base(name) { }
    public void Fly() => Console.WriteLine($"{Name} is flying!");
    public override void MakeANoise() => Console.WriteLine($"{Name} says 'I am supercow!'");
}

泛型農場類別


public class Farm<T> : IEnumerable<T> where T : Animal
{
    private readonly List<T> _animals = new List<T>();
    public List<T> Animals => _animals;

    public IEnumerator<T> GetEnumerator() => _animals.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _animals.GetEnumerator();

    public void MakeNoises() => _animals.ForEach(a => a.MakeANoise());
    public void FeedTheAnimals() => _animals.ForEach(a => a.Feed());

    // 示範型別轉換與泛型回傳
    public Farm<Cow> GetCows()
    {
        var cowFarm = new Farm<Cow>();
        foreach (var a in _animals)
            if (a is Cow c) cowFarm.Animals.Add(c);
        return cowFarm;
    }
}

使用示範


var farm = new Farm<Animal>();
farm.Animals.Add(new Cow("Jack"));
farm.Animals.Add(new Chicken("Vera"));
farm.Animals.Add(new Chicken("Sally"));
farm.Animals.Add(new SuperCow("Kevin"));

farm.MakeNoises();

var dairyFarm = farm.GetCows();
dairyFarm.FeedTheAnimals();

foreach (var cow in dairyFarm)
    if (cow is SuperCow sc) sc.Fly();

6. 進階觀念補充

  • 協變/逆變:IEnumerable<out T> 允許 Farm<Cow> 隱性轉為 IEnumerable<Animal>;Action<in T> 相反。介面設計時善用 in/out 提升彈性。
  • 泛型方法:public TResult Convert<TSource, TResult>(TSource input),型別推論讓呼叫更簡潔。
  • 泛型委派:Func<T, TResult>、Action<T> 是最常用的泛型委派,LINQ 大量依賴它們。
  • 效能:值型別使用泛型避免裝箱/拆箱;參考型別共用同一組 JIT 程式碼(Canonical instantiation),記憶體友善。

總結

自訂泛型的關鍵三步驟:定義型別參數 → 加上必要約束 → 善用 default 與介面約束實現多型。農場範例展示了「以基類型別參數化集合、保留子類型別行為、支援型別安全篩選」的經典模式。掌握這套思維,您就能設計出如 Repository<TEntity>、Pipeline<TContext> 等高復用、強型別的核心架構元件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved