C# 中的类型安全即发即弃异步委托调用 [英] Typesafe fire-and-forget asynchronous delegate invocation in C#

查看:17
本文介绍了C# 中的类型安全即发即弃异步委托调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近发现自己需要一种类型安全的即发即弃"机制来异步运行代码.

理想情况下,我想做的是:

Ideally, what I would want to do is something like:

var myAction = (Action)(() => Console.WriteLine("yada yada"));
myAction.FireAndForget(); // async invocation

不幸的是,在没有相应 EndInvoke() 的情况下调用 BeginInvoke() 的明显选择不起作用 - 它会导致缓慢的资源泄漏(因为异步状态是由运行时持有并且从未释放...它期望最终调用 EndInvoke().我也无法在 .NET 线程池上运行代码,因为它可能需要很长时间才能完整(建议只在线程池上运行相对短暂的代码) - 这使得无法使用 ThreadPool.QueueUserWorkItem().

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().

最初,我只需要签名匹配 ActionAction<...>Func<...> 的方法使用此行为..所以我把一组扩展方法(见下面的清单)放在一起,让我在不遇到资源泄漏的情况下做到这一点.每个版本的 Action/Func 都有重载.

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.

不幸的是,我现在想将此代码移植到 .NET 4,其中 Action 和 Func 的泛型参数数量已大大增加.在我编写一个 T4 脚本来生成这些之前,我还希望找到一种更简单更优雅的方法来做到这一点.欢迎任何想法.

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<>

}

推荐答案

您可以将 EndInvoke 作为 AsyncCallback 传递给 BeginInvoke:

You can pass EndInvoke as AsyncCallback for BeginInvoke:

Action<byte[], int, int> action = // ...

action.BeginInvoke(buffer, 0, buffer.Length, action.EndInvoke, null);

这有帮助吗?

这篇关于C# 中的类型安全即发即弃异步委托调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆