// 錯誤:CS1660 無法將 lambda 轉換為 'System.Delegate' (非具體委派型別)
MyTimer.Dispatcher.Invoke(() => DoSomething());
Dispatcher.Invoke(Delegate method, params object[] args) 參數為抽象 Delegate,編譯器無法推論 lambda 的具體簽章。
.NET 3.5 內建 Action, Action<T>, Action<T1,T2> 等具體委派,完美配合 lambda。
Action<string, Brush> updateTimer = (label, brush) =>
{
MyTime.Content = label;
MyTime.Background = brush;
};
if (!MyTime.Dispatcher.CheckAccess())
{
MyTime.Dispatcher.Invoke(updateTimer, newLabel, nextBrush);
}
else
{
updateTimer(newLabel, nextBrush);
}
public static class WPFExtensions
{
public static void InvokeIfNeeded(this Control ctrl, Action action)
{
if (!ctrl.Dispatcher.CheckAccess()) ctrl.Dispatcher.Invoke(action);
else action();
}
public static void InvokeIfNeeded<T>(this Control ctrl, Action<T> action, T arg)
{
if (!ctrl.Dispatcher.CheckAccess()) ctrl.Dispatcher.Invoke(action, arg);
else action(arg);
}
public static void InvokeIfNeeded<T1, T2>(this Control ctrl, Action<T1, T2> action, T1 arg1, T2 arg2)
{
if (!ctrl.Dispatcher.CheckAccess()) ctrl.Dispatcher.Invoke(action, arg1, arg2);
else action(arg1, arg2);
}
// 可依需求繼續擴充更多參數版本
}
this.InvokeIfNeeded(() => lbl.Text = "Done");
this.InvokeIfNeeded((msg, color) => { lbl.Text = msg; lbl.ForeColor = color; }, "Hello", Brushes.Red);
WPF 為了 API 通用性採用抽象
Delegate+params object[],犧牲了類型安全與編譯器推論。**正確做法是在專案層建立類型安全的包裝層** (如上述擴充方法),而非每處手寫委派變數。
Control.Invoke(Delegate) 同樣問題,同樣解法。object 陣列參數。Delegate/object[] 的舊版 API。Lambda 無法直接轉為抽象 Delegate 是 C# 型別系統的限制,而非缺陷。善用 Action/Func 具體委派 + 擴充方法封裝,即可在享受 lambda 簡潔語法的同時,保持類型安全、消除重複樣板代碼。