【问题标题】:How do I catch exceptions from within Action<T> or containing an anonymous method in c#?如何从 Action<T> 中捕获异常或在 c# 中包含匿名方法?
【发布时间】:2016-09-06 19:13:59
【问题描述】:

我正在尝试创建一个与此类似的全局异常方法,以便显示异常以及在异常之前可能已捕获的任何数据

public class ServiceResponse<T> {
   public T Data {get;set;}
   public List<Exception> Errors {get;set;}
}

public static ServiceResponse<T> GetServiceResponse<T>(this ServiceResponse<T> response, Action<T> action)  
    {
        try
        {
           action(response.Data);
        }
        catch (Exception ex)
        {
            if (response.Errors == null)
            {
                response.Errors = new List<Error>();
            }
            response.Errors.Add(ex);
        }
        return response;

    }

它会被这样调用:

await Task.WhenAll(myTask1, myTask2).ContinueWith(t =>{ /*this is needed */ });
var response = new ServiceResponse<myData>();
response = response.GetServiceResponse(async r =>
                {
                    var info= await myTask1;
                    r.Status= info.status;
                    r.Timeout = info.Timout;
                })
           .GetServiceResponse(async r => { r.Hybrid = await myTask2; });

问题是当Task1 或Task2 发生异常时,它永远不会被GetServiceResponse 方法的catch 捕获。

【问题讨论】:

  • 您有一个实际上是Func,而不是Action 的“操作”,并且您的委托返回一个您刚刚放在地板上的值,这应该是一个非常危险的信号.任何时候你只是在地板上丢掉价值,很有可能出现问题,就像这里的情况一样。
  • Func 是一个错字。

标签: c# exception lambda error-handling


【解决方案1】:

那是因为该方法没有抛出异常。它返回一个Task,最终进入Faulted 状态。

如果您想处理异步方法,您需要创建一个额外的方法重载,其中委托返回 Task(另一个返回 Task&lt;T&gt;),这样您就可以捕获任何异常方法抛出,但还添加一个延续来处理存储在结果 Task 中的任何异常。

【讨论】:

  • 你能举个例子吗?我是否尝试将返回值从 Task> 更改为 Task ?或 Action 到 Task> ?
  • @Brian 就像我在回答中所说的那样,您需要接受一个返回 Task 的委托,目前您的委托可以返回 anything,而您可以忽略它返回值,不管是不是Task
【解决方案2】:

我能够通过将任务作为单独的参数传递来捕获异常,然后检查 IsFaulted 属性:

public static ServiceResponse<T> GetServiceResponse<T, K>(this ServiceResponse<T> response, Action<T, Task<K>> action, Task<K> task) where T : class
    {
        try
        {
            if (!task.IsFaulted)
            {
                action(response.Data, task);

            }
            else
            {
                if (response.Errors == null)
                {
                    response.Errors = new List<Error>();
                }
                if (task.Exception != null && task.Exception.InnerException != null)
                {
                    throw task.Exception.InnerException;
                }
                throw new Exception("Faulted");

            }
        }
        catch (Exception ex)
        {
            if (response.Errors == null)
            {
                response.Errors = new List<Exception>();
            }
            Debug.WriteLine(ex.Message);
            response.Errors.Add(ex);
        }
        return response;

    }

【讨论】:

  • 像这样传入Task 没有任何意义。您传递的方法返回Task。让该方法接受Task 作为参数对该方法没有任何意义,也无法通过该任务提供其执行结果,考虑到您是如何构造它的。当action 返回错误的Task 时,您的代码没有为您提供执行操作的方法,因为您实际上仍然没有观察到Task,而是仍然将其放在地板上。
猜你喜欢
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2021-12-23
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 2013-08-11
相关资源
最近更新 更多