.NET 2.0 引入泛型、匿名方法與 Predicate<T> 委派,使 List<T>.FindAll 等內建演算法極具表達力。本文示範如何在**自訂集合類別**中實作相同模式。
public delegate bool Predicate<T>(T obj);
List<T>.FindAll 內部邏輯相當於:
public List<T> FindAll(Predicate<T> match)
{
List<T> result = new List<T>();
foreach (T item in this)
if (match(item)) result.Add(item);
return result;
}
using System;
using System.Collections.Generic;
using System.Text;
public class MyVec<T> : IEnumerable<T>
{
private List<T> _inner = new List<T>();
// 運算子多載:支援 vec += item 語法
public static MyVec<T> operator +(MyVec<T> vec, T item)
{
vec._inner.Add(item);
return vec;
}
// 實作 FindAll
public MyVec<T> FindAll(Predicate<T> match)
{
MyVec<T> result = new MyVec<T>();
foreach (T item in _inner)
if (match(item)) result += item;
return result;
}
// 實作 IEnumerable<T> 支援 foreach
public IEnumerator<T> GetEnumerator() => _inner.GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (T item in _inner) sb.Append(item).Append(',');
if (sb.Length > 0) sb.Length--; // 移除尾端逗號
return sb.ToString();
}
}
static void Main()
{
MyVec<int> vec = new MyVec<int>();
vec += 12;
vec += 15;
vec += 32;
// 匿名方法作為 Predicate
MyVec<int> found = vec.FindAll(delegate(int x) { return x < 20; });
// C# 3.0+ Lambda 更簡潔:vec.FindAll(x => x < 20);
Console.WriteLine("原始:" + vec); // 12,15,32
Console.WriteLine("找到:" + found); // 12,15
Console.ReadLine();
}
// 存在性檢查
public bool Exists(Predicate<T> match) => _inner.Exists(match);
// 單一元素查詢
public T Find(Predicate<T> match) => _inner.Find(match);
public int FindIndex(Predicate<T> match) => _inner.FindIndex(match);
// 轉換
public MyVec<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
MyVec<TOutput> result = new MyVec<TOutput>();
foreach (T item in _inner) result += converter(item);
return result;
}
// 排序 (需 T 實作 IComparable<T>)
public void Sort() => _inner.Sort();
public void Sort(Comparison<T> comparison) => _inner.Sort(comparison);
// 迴圈動作
public void ForEach(Action<T> action) => _inner.ForEach(action);
Predicate<T>)、轉換邏輯 (Converter<T, TOutput>)、動作 (Action<T>) 參數化,集合本身只負責遍歷與控制流程。foreach、LINQ 擴充方法 (.Where(), .Select() 等)。List<T> 為底層,實務上可換成陣列、鏈結串列、樹狀結構等,對外介面不變。+= 語法糖,提升流暢度 (Fluent API)。掌握 Predicate<T>/Action<T>/Func<T, TResult> 委派模式,即可為任意資料結構賦予 LINQ 風格的查詢能力,這正是 C# 函數式特性威力的核心體現。