簡介
Params Collections 是 C# 12 中引入的新特性,它擴展了傳統的 params 關鍵字功能,使其不僅支持數組,還能支持各種集合類型。這個特性使得方法能夠接受可變數量的參數,並且這些參數可以自動轉換為指定的集合類型。
關鍵特點:
- 可變參數:調用者可以傳遞任意數量的參數(包括零個)。
- 類型安全:
params參數是強類型的,編譯器確保參數類型匹配。 - 單一
params參數:一個方法只能有一個params參數,且必須是最後一個參數。 C# 12擴展:支持非數組集合類型(如List<T>,Span<T>),適合高性能或特定場景。
核心特性
支持任意集合類型
- 可指定
List<T>、Span<T>、IReadOnlyCollection<T>等作為參數類型
public void LogEntries(params List<string> messages) { ... }
自動集合構造
- 編譯器自動將離散參數轉換為目標集合類型實例
AnalyzeNumbers(10, 20, 30);
// 等效於:
AnalyzeNumbers(new List<int> { 10, 20, 30 });
與現有 params 兼容
- 傳統
params T[]仍然有效 - 新語法不會破壞已有代碼
傳統 params 關鍵字
在 C# 12 之前,params 關鍵字只能用於數組:
// 傳統的 params 數組用法
public void ProcessNumbers(params int[] numbers)
{
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
// 調用方式
ProcessNumbers(1, 2, 3, 4, 5);
Params Collections 的新特性
C# 12 擴展了 params 關鍵字,使其能夠用於任何集合類型,只要該類型滿足特定條件。
基本語法
// 使用 params 與集合類型
public void ProcessNumbers(params List<int> numbers)
{
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
// 調用方式不變
ProcessNumbers(1, 2, 3, 4, 5);
支持的條件
要使集合類型能夠與 params 關鍵字一起使用,必須滿足以下條件之一:
- 集合類型必須有一個無參數的構造函數
- 集合類型必須有一個
Add方法,用於添加元素 - 集合類型必須實現
IEnumerable<T>
自定義集合與 params
// 自定義集合類
public class NumberCollection : IEnumerable<int>
{
private readonly List<int> _numbers = new();
public void Add(int number) => _numbers.Add(number);
public IEnumerator<int> GetEnumerator() => _numbers.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
// 使用自定義集合作為 params 參數
public void ProcessNumbers(params NumberCollection numbers)
{
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
// 調用
ProcessNumbers(1, 2, 3, 4, 5);
實際應用示例
與 Span 和 ReadOnlySpan 結合使用
// 使用 Span 作為 params 參數
public void ProcessData(params Span<int> data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] *= 2;
}
}
// 調用
int[] array = [1, 2, 3, 4, 5];
ProcessData(array);
Console.WriteLine(string.Join(", ", array)); // 輸出: 2, 4, 6, 8, 10
與 Immutable Collections 結合使用
using System.Collections.Immutable;
// 使用不可變集合作為 params 參數
public void ProcessItems(params ImmutableArray<string> items)
{
foreach (var item in items)
{
Console.WriteLine(item);
}
}
// 調用
ProcessItems("apple", "banana", "cherry");
高級用法
泛型方法與 params 集合
// 泛型方法中使用 params 集合
public void ProcessCollection<T>(params List<T> collection)
where T : notnull
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
// 調用
ProcessCollection("a", "b", "c"); // 字符串列表
ProcessCollection(1, 2, 3); // 整數列表
與模式匹配結合使用
// 使用模式匹配處理 params 集合
public void HandleValues(params int[] values)
{
switch (values)
{
case [var first, .. var middle, var last]:
Console.WriteLine($"首: {first}, 尾: {last}, 中間有 {middle.Length} 個元素");
break;
case [var single]:
Console.WriteLine($"單個值: {single}");
break;
case []:
Console.WriteLine("空集合");
break;
}
}
// 調用
HandleValues(1, 2, 3, 4, 5); // 輸出: 首: 1, 尾: 5, 中間有 3 個元素
HandleValues(42); // 輸出: 單個值: 42
HandleValues(); // 輸出: 空集合
與接口結合使用
// 使用接口作為 params 參數
public void ProcessEnumerables(params IEnumerable<int>[] collections)
{
foreach (var collection in collections)
{
int sum = collection.Sum();
Console.WriteLine($"集合總和: {sum}");
}
}
// 調用
ProcessEnumerables(
new List<int> { 1, 2, 3 },
new int[] { 4, 5, 6 },
new HashSet<int> { 7, 8, 9 }
);
高性能求和(使用 Span<T>)
public decimal Average(params Span<decimal> numbers)
{
if (numbers.Length == 0) return 0;
decimal sum = 0;
foreach (var num in numbers)
{
sum += num;
}
return sum / numbers.Length;
}
Console.WriteLine(Average(1.5m, 2.5m, 3.5m)); // 輸出: 2.5
- 使用
Span<decimal>避免數組分配,提高性能。 - 適合處理大量數值計算。
適用場景
- 簡化方法調用:允許調用者傳遞任意數量的參數,減少重載需求。
- 處理集合數據:適合處理列表、數組或序列,例如日誌記錄、字符串連接、數學計算。
- 高性能場景(
C# 12+):使用Span<T>或ReadOnlySpan<T>減少堆分配,優化性能。 - 與本機代碼交互:
Span<T>類型的params參數適合傳遞連續內存塊。 - 靈活接口設計:為方法提供通用接口,支持不同數量的輸入。