在C#中,Where關鍵字主要有兩種用途
1、在泛型約束中限制類型參數
2、在LINQ查詢中篩選數據
本文主要介紹where關鍵字在在泛型約束中的使用
? ? ? ?泛型定義中的?where
?子句指定對用作泛型類型、方法、委托或本地函數中類型參數的參數類型的約束。通過使用?where
?關鍵字和泛型約束,可以創建更安全、更靈活的泛型類和方法的實現。
使用的對象
Where可以對類、方法、委托和接口使用。
類的使用,例如C#中常用的List<T>
方法的使用,
public void MyFunc<T>() where T:struct
委托的使用
public delegate void MyDelete<T>() where T : class;
接口的使用
約束分類
約束 | 說明 |
where T : struct | T必須是值類型,如int,double等 |
where T : class | T必須是引用類型,如string,List<T>等 |
where T : new() | T必須有無參構造函數,即T參數可以通過使用new關鍵字創建實例。當與其他約束一起使用時,new() 約束必須最后指定。 |
where T : 基類 | T 必須繼承自某個基類 |
where T : 接口 | T 必須實現某個接口 |
where T : U | T 必須派生自 U |
where T : struct
public class MyClass<T> where T : struct
{public T Value { get; set; }
}
例子:
// 只接受值類型的泛型方法
public class ValueCalculator<T> where T : struct
{public T Add(T a, T b){return (dynamic)a + (dynamic)b; // 簡單示例,實際中需要更安全的實現}
}// 使用示例
class Program
{static void Main(){var intCalc = new ValueCalculator<int>();Console.WriteLine(intCalc.Add(5, 3)); // 輸出 8// 下面這行會編譯錯誤,因為 string 是引用類型// var stringCalc = new ValueCalculator<string>();}
}
where T : class
public class MyClass<T> where T : class
{public T Value { get; set; }
}
例子?
public class Repository<T> where T : class, new()
{private List<T> items = new List<T>();public T CreateItem(){var newItem = new T(); // 可以實例化,因為有 new() 約束items.Add(newItem);return newItem;}public void DisplayCount(){Console.WriteLine($"Items count: {items.Count}");}
}// 使用示例
class Program
{class Customer{public string Name { get; set; }}static void Main(){var repo = new Repository<Customer>();var customer = repo.CreateItem();customer.Name = "John Doe";repo.DisplayCount(); // 輸出 Items count: 1}
}
where T : new()
public class Factory<T> where T : new()
{public T CreateInstance(){return new T();}
}
where T : 基類
public class AnimalShelter<T> where T : Animal
{public void Shelter(T animal){animal.Feed();}
}
where T : 接口
public class Sorter<T> where T : IComparable<T>
{public void Sort(T[] array){Array.Sort(array);}
}
?例子
using System;// 定義一個接口
public interface IDisplayable
{void Display();
}// 實現接口的類
public class Product : IDisplayable
{public string Name { get; set; }public void Display(){Console.WriteLine($"Product: {Name}");}
}// 使用 where 約束確保 T 實現 IDisplayable
public class DisplayManager<T> where T : IDisplayable
{public void Show(T item){item.Display(); // 安全調用,因為知道 T 有 Display 方法}
}// 使用示例
class Program
{static void Main(){var product = new Product { Name = "Laptop" };var manager = new DisplayManager<Product>();manager.Show(product);}
}
where T : U
public class DerivedContainer<T, U> where T : U
{// T 必須繼承自 U 或實現 U(如果 U 是接口)
}
?例子
public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some animal sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark!");}
}// 約束 T 必須繼承自 Animal
public class AnimalShelter<T> where T : Animal
{public void LetAnimalMakeSound(T animal){animal.MakeSound(); // 可以調用 Animal 的方法}
}// 使用示例
class Program
{static void Main(){var shelter = new AnimalShelter<Dog>();shelter.LetAnimalMakeSound(new Dog()); // 輸出 "Bark!"}
}
多重約束
可以為類型參數指定多個約束
需要注意的是:當與其他約束一起使用時,new() 約束必須最后指定。
public class MyClass<T> where T : class, IDisposable, new()
{}
多個類型參數的約束
對于多個類型參數,每個都可以有自己的約束:
public class MyClass<TKey, TValue>where TKey : IComparable<TKey>where TValue : class,new(){}
約束的優點
1、增強類型安全?- 編譯器可以在編譯時捕獲類型不匹配的錯誤。
2、減少運行時轉換?- 避免不必要的類型檢查和轉換。
3、啟用更多操作?- 知道類型參數具有某些特性(如特定方法或構造函數)后,可以在泛型代碼中?使用這些特性。
4、不會對性能產生可測量的影響。
總結:合理使用泛型約束可以顯著提高代碼質量和安全性,但應該避免過度使用導致不必要的復雜性。在大多數情況下,優點遠大于缺點,特別是在開發庫代碼或框架時。