博客 / 詳情

返回

C# Params Collections 詳解:比 params T[] 更強大的新語法

簡介

Params CollectionsC# 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 參數適合傳遞連續內存塊。
  • 靈活接口設計:為方法提供通用接口,支持不同數量的輸入。
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.