【发布时间】:2011-02-16 15:08:17
【问题描述】:
我最近发现自己需要一种类型安全的“即发即弃”机制来异步运行代码。
理想情况下,我想做的是:
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<>
}
【问题讨论】:
-
很酷的问题。痛苦的代码!它们唯一的共同点是它们都是 MulticastDelegate。我不确定是否会有一种类型安全的方式来节食代码。 MS 首先是如何生成所有这些的?
-
@spender:编译器会自动为每个委托类型生成
BeginInvoke/EndInvoke方法,这些方法对委托的参数进行强类型化。 -
当然。在我看来,它鼓励大量的样板代码,我很惊讶 .net4 没有引入一种更通用(或超通用)的方式来声明这些类型的结构......尽管我在大多数情况下都同意这一点代码,参数列表的长度不会超过5个左右。
标签: c# generics asynchronous delegates .net-4.0