问题描述
我最近发现自己需要一个类型安全的发射后不管的机制运行code异步的。
在理想情况下,我会想要做的是一样的东西:
VAR MyAction的=(行动)(()=> Console.WriteLine(内容十分重要));
myAction.FireAndForget(); //异步调用
不幸的是,在调用的不二之选的BeginInvoke()
没有相应的 EndInvoke会()
不工作 - 它结果在一个缓慢的资源泄漏(因为ASYN状态运行时举行,从未发布...它期待 EndInvoke会最终调用()
。我也不能运行在.NET线程池的code,因为它可能需要很长的时间才能完成(它的建议线程池只能运行相对较短code) - 这使得它无法使用 ThreadPool.QueueUserWorkItem()
。
起初,我只需要方法的签名匹配这一行为动作
,动作< ...>
或 Func键< ...>
。所以,我放在一起了一套扩展方法(参见下面的列表),这让我做到这一点没有运行到资源泄漏。有重载每个版本的动作/函数的。
不幸的是,我现在想将这个code到.NET 4中的行动和Func键泛型参数的数量已大幅增加。之前我写了一个T4脚本生成这些,我也希望能找到一个更简单更优雅的方式来做到这一点。任何想法是值得欢迎的。
公共静态类AsyncExt
{
公共静态无效FireAndForget(这个动作的动作)
{
action.BeginInvoke(OnActionCompleted,动作);
}
公共静态无效FireAndForget< T1>(这个动作< T1>的行动,T1 ARG1)
{
action.BeginInvoke(ARG1,OnActionCompleted< T1>中的动作);
}
公共静态无效FireAndForget< T1,T2>(这个动作< T1,T2>的行动,T1 ARG1,T2 ARG2)
{
action.BeginInvoke(ARG1,ARG2,OnActionCompleted&所述; T1,T2>中的动作);
}
公共静态无效FireAndForget< TResult>(这个函数功能:LT; TResult> FUNC,TResult ARG1)
{
func.BeginInvoke(OnFuncCompleted< TResult>中FUNC);
}
公共静态无效FireAndForget< T1,TResult>(这个函数功能:其中,T1,TResult>的行动,T1 ARG1)
{
action.BeginInvoke(ARG1,OnFuncCompleted< T1,TResult>中的动作);
}
// FireAndForget和更多的重载LT; ..>()行动< ..>以及FUNC< ..>
私有静态无效OnActionCompleted(IAsyncResult的结果)
{
VAR行动=(动作)result.AsyncState;
action.EndInvoke(结果);
}
私有静态无效OnActionCompleted< T1>(IAsyncResult的结果)
{
VAR行动=(动作< T1>)result.AsyncState;
action.EndInvoke(结果);
}
私有静态无效OnActionCompleted< T1,T2>(IAsyncResult的结果)
{
VAR行动=(动作< T1,T2>)result.AsyncState;
action.EndInvoke(结果);
}
私有静态无效OnFuncCompleted< TResult>(IAsyncResult的结果)
{
VAR FUNC =(Func键< TResult>)result.AsyncState;
func.EndInvoke(结果);
}
私有静态无效OnFuncCompleted< T1,TResult>(IAsyncResult的结果)
{
VAR FUNC =(Func键< T1,TResult>)result.AsyncState;
func.EndInvoke(结果);
}
// OnActionCompleted&所述的更重载;>和OnFuncCompleted<>
}
您可以通过EndInvoke会作为的AsyncCallback的BeginInvoke的:
动作<字节[],INT,INT>行动= // ...
action.BeginInvoke(缓冲液,0,buffer.Length,action.EndInvoke,空);
帮助吗?
I recently found myself needing a typesafe "fire-and-forget" mechanism for running code asynchronously.
Ideally, what I would want to do is something like:
var myAction = (Action)(() => Console.WriteLine("yada yada"));
myAction.FireAndForget(); // async invocation
Unfortunately, the obvious choice of calling BeginInvoke()
without a corresponding EndInvoke()
does not work - it results in a slow resource leak (since the asyn state is held by the runtime and never released ... it's expecting an eventual call to EndInvoke()
. I also can't run the code on the .NET thread pool because it may take a very long time to complete (it's advised to only run relatively short-lived code on the thread pool) - this makes it impossible to use the ThreadPool.QueueUserWorkItem()
.
Initially, I only needed this behavior for methods whose signature matches Action
, Action<...>
, or Func<...>
. So I put together a set of extension methods (see listing below) that let me do this without running into the resource leak. There are overloads for each version of Action/Func.
Unfortunately, I now want to port this code to .NET 4 where the number of generic parameters on Action and Func have been increased substantially. Before I write a T4 script to generate these, I was also hoping to find a simpler more elegant way to do this. Any ideas are welcome.
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<>
}
You can pass EndInvoke as AsyncCallback for BeginInvoke:
Action<byte[], int, int> action = // ...
action.BeginInvoke(buffer, 0, buffer.Length, action.EndInvoke, null);
Does that help?
这篇关于类型安全发射后忘记在C#中的异步委托调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!