如何制作通用委托EndInvoke?

时间:2014-02-17 06:52:17

标签: c# generics delegates iasyncresult

所以我有以下内容:

private delegate Foo1 GetFooAsync1(Foo1 foo1);
private delegate Foo2 GetFooAsync2(Foo2 foo2);
private delegate Foo3 GetFooAsync3(Foo3 foo3);
private delegate Foo4 GetFooAsync4(Foo4 foo4);

private FooAsync1 foo1;
private FooAsync2 foo2;
private FooAsync3 foo3;
private FooAsync4 foo4;

然后列表继续,然后在一个方法中我不想在每个EndInvoke上放一个try catch,因为有时候它会抛出一个异常,但它不应该停止系统,继续另一个Foos ..如果每个人都试着抓住它,那么在这个方法中占据了很多空间。

是否有通用方式来调用结束调用?所以我可以返回预期的结果吗?

var result1 = foo1.EndInvoke(fooIAsyncResult);

1 个答案:

答案 0 :(得分:0)

为了以通用方式实现这一点,您需要声明一个覆盖EndInvoke的扩展方法,如下所示:

public static class DelegateExtensions
{
    public static TResult EndInvoke<TDelegate, TResult>(this TDelegate asyncCaller, IAsyncResult asyncResult) where TDelegate : System.Delegate
    {
        TResult result = default(TResult);

        try
        {
            result = asyncCaller.EndInvoke(asyncResult);
        }
        catch ( Exception ex)
        {
            LogExceptionMessageOrWhatever(ex.Message);
            throw;
        }

        return result;
    }
}

但是,该过程将生成编译器错误。为什么? System.Delegate类是一个不能在泛型约束中使用的特殊类。

所以你不能摆脱约束,并使用反射来调用正确的程序吗?

我想你可以,但这违背了使用泛型的目的。更好的解决方案是使您的委托具有通用性,然后重写扩展方法以仅定位该委托。

public delegate TFooResult GetFooAsync<TFooResult>();

public static class GetFooAsyncExtensions
{
    public static TFooResult EndInvoke<TFooResult>(this GetFooAsync<TFooResult> asyncCaller, IAsyncResult asyncResult)
    {
        TFooResult result = default(TFooResult);

        try
        {
            result = asyncCaller.EndInvoke(asyncResult);
        }
        catch ( Exception ex )
        {
            LogExceptionMessageOrWhatever(ex.Message);
            throw;
        }

        return result;
    }
}

现在你像往常一样打电话给EndInvoke。该框架将自动使用您的版本。

private void Main()
{
    Foo1Result foo1 = null;

    var foo1Factory = new GetFooAsync<Foo1Result>(
        () =>
        {
            return new Foo1Result();
        });


    foo1Factory.BeginInvoke(
        callback: asyncResult =>
            {
                foo1 = foo1Factory.EndInvoke(asyncResult);
            },
            @object: null);
}