我最近发现自己需要一个类型安全的异步“打火机”机制。
理想情况下,我想要做的是:
var myAction = (Action)(() => Console.WriteLine("yada yada"));
myAction.FireAndForget(); // async invocation
很遗憾,显而易见的选择——调用没有相应 EndInvoke()
的 BeginInvoke()
不起作用——它会导致缓慢的资源泄漏(因为异步状态由运行时持有且从不释放...期望最终调用 EndInvoke()
)。我也不能在.NET线程池上运行代码,因为它可能需要很长时间才能完成(建议只在线程池上运行相对较短的代码),这使得使用 ThreadPool.QueueUserWorkItem()
成为不可能。
最初,我只需要对匹配 Action
, Action<...>
, 或 Func<...>
签名的方法执行此操作。所以我编写了一组扩展方法(见下面的清单),让我可以执行此操作而不会遇到资源泄漏。每个版本的 Action/Func 都有重载。
不幸的是,现在我想将此代码移植到.NET 4上,在那里Action和Func上的泛型参数数量已大大增加。 在编写T4脚本生成这些之前,我希望能找到更简单、更优雅的方式来做到这一点。欢迎任何想法。
public static class AsyncExt
{
public static void FireAndForget( this Action action )
{
action.BeginInvoke(OnActionCompleted, action);
}
public static void FireAndForget<T1>( this Action<T1> action, T1 arg1 )
{
action.BeginInvoke(arg1, OnActionCompleted<T1>, action);
}
public static void FireAndForget<T1,T2>( this Action<T1,T2> action, T1 arg1, T2 arg2 )
{
action.BeginInvoke(arg1, arg2, OnActionCompleted<T1, T2>, action);
}
public static void FireAndForget<TResult>(this Func<TResult> func, TResult arg1)
{
func.BeginInvoke(OnFuncCompleted<TResult>, func);
}
public static void FireAndForget<T1,TResult>(this Func<T1, TResult> action, T1 arg1)
{
action.BeginInvoke(arg1, OnFuncCompleted<T1,TResult>, action);
}
// more overloads of FireAndForget<..>() for Action<..> and Func<..>
private static void OnActionCompleted( IAsyncResult result )
{
var action = (Action)result.AsyncState;
action.EndInvoke(result);
}
private static void OnActionCompleted<T1>( IAsyncResult result )
{
var action = (Action<T1>)result.AsyncState;
action.EndInvoke( result );
}
private static void OnActionCompleted<T1,T2>(IAsyncResult result)
{
var action = (Action<T1,T2>)result.AsyncState;
action.EndInvoke(result);
}
private static void OnFuncCompleted<TResult>( IAsyncResult result )
{
var func = (Func<TResult>)result.AsyncState;
func.EndInvoke( result );
}
private static void OnFuncCompleted<T1,TResult>(IAsyncResult result)
{
var func = (Func<T1, TResult>)result.AsyncState;
func.EndInvoke(result);
}
// more overloads of OnActionCompleted<> and OnFuncCompleted<>
}
BeginInvoke
/EndInvoke
方法,这些方法是针对委托参数进行强类型化的。 - LBushkin