C#扩展方法(Extension Method)
在 C# 中,扩展方法(Extension Method)的语法允许你通过 this 关键字将第一个参数隐式传递,因此在调用时 不需要显式传递第一个参数。
这里有个扩展方法
public static Task<T> InvokeAsync<T>(this Control control, Func<T> func)
{var tcs = new TaskCompletionSource<T>();control.BeginInvoke(new Action(() =>{try{tcs.SetResult(func());}catch (Exception ex){tcs.SetException(ex);}}));return tcs.Task;
}
扩展方法的特点:
**隐式 control 参数:**this Control control 表示这是一个扩展方法,作用在 Control 类型上。当你调用 _uiControl.InvokeAsync(showDialogFunc) 时,_uiControl 会自动作为 control 参数传递,而 showDialogFunc 是第二个参数 func。
**泛型参数 <T>:**InvokeAsync<T> 的泛型参数 <T> 会根据 func 的返回值类型自动推断。例如,如果 showDialogFunc 返回 string,则 T 会被推断为 string。
调用时的参数传递:
return await _uiControl.InvokeAsync(showDialogFunc);
_uiControl 是扩展方法的第一个参数 control(通过 this Control control 隐式传递)。
showDialogFunc 是第二个参数 func。
为什么不需要显式传递两个参数?
扩展方法的语法简化了调用方式:
原本需要写为 InvokeAsync(_uiControl, showDialogFunc)。
但因为 this Control control 的存在,你可以直接写成 _uiControl.InvokeAsync(showDialogFunc),编译器会自动将 _uiControl 作为第一个参数。
完整流程解析:
线程切换:
如果当前线程不是 UI 线程,control.BeginInvoke 会将 func 委托的调用调度到 UI 线程。
如果当前已经是 UI 线程,BeginInvoke 会直接执行(同步或异步取决于具体实现)。
异步包装:
TaskCompletionSource 用于将 BeginInvoke 的异步操作包装成一个 Task。
当 func 在 UI 线程执行完成后:
如果成功,调用 tcs.SetResult(func()) 设置结果。
如果抛出异常,调用 tcs.SetException(ex) 传递异常。
返回 Task:
最终返回的 tcs.Task 可以让调用者通过 await 等待结果。
总结:
**扩展方法的语法:通过 this 关键字隐式传递第一个参数(control),调用时不需要显式传递。
泛型推断:**根据 func 的返回值类型自动推断泛型参数 。
线程安全: BeginInvoke 确保 func 在 UI 线程执行,并通过 Task 提供异步支持。