【问题标题】:How to make a generic delegate EndInvoke?如何制作通用委托 EndInvoke?
【发布时间】:2014-03-16 08:45:10
【问题描述】:

所以我有以下内容:

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.. 如果每个人都有一个 try catch ,那么会在方法中占用太多空间。

有没有一种通用的方式来调用结束调用?所以我可以返回预期的结果?

var result1 = foo1.EndInvoke(fooIAsyncResult);

【问题讨论】:

  • .net Func 和 Action 中有两个 biltin 代表使用它,覆盖 90% 的场景
  • 你可以传递一个lambda表达式stackoverflow.com/questions/14297633/…
  • 我不明白您为什么要编写将委托作为参数的委托。我写了一个没有这种嵌套的解决方案。如果这没有帮助,请将示例替换为您的实际代码。

标签: c# generics delegates iasyncresult


【解决方案1】:

为了以通用方式实现这一点,您需要声明一个覆盖 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    相关资源
    最近更新 更多