【问题标题】:Can an exception be handled in another class, assembly, or abstract class?可以在另一个类、程序集或抽象类中处理异常吗?
【发布时间】:2011-12-04 21:28:07
【问题描述】:

我发现需要多次复制并粘贴以下错误处理代码。在 Catch 语句中工作时我有哪些选择?

  • 在此过程中,我是否会丢失有价值的信息? (例如:异常是在另一个异常中重新包装,还是堆栈信息丢失)

  • 如何区分 myAbstractClass 中的“抛出”和下面的 Select 方法中的“抛出”?

这是我要复制的示例代码

public class StackUserDataSource : AbstractEnhancedTableDataSource<StackUserDataServiceContext>
{
  //.. stuff

 public IEnumerable<StackUserDataModel> Select() 
    {
        try
        {
            var results = from c in _ServiceContext.StackUserTable
                          select c;

            var query = results.AsTableServiceQuery();
            var queryResults = query.Execute();

            return queryResults;
        }
        catch (StorageClientException e)
        {

           // Todo: consider sticking this in another central location    
            switch (e.ErrorCode)
            {
                case StorageErrorCode.AccessDenied:
                    break;
                case StorageErrorCode.AccountNotFound:
                    break;
                case StorageErrorCode.AuthenticationFailure:
                    break;
                // ... Yadda yadda, handle some exceptions, not others.. this is a demo.
                case StorageErrorCode.TransportError:
                    break;
                default:
                    break;
            }
            throw;
        }
    }

更新

我怀疑这是可能的,但我可以在外部库中动态捕获和过滤异常吗?这个概念是这样的

        try
        {
            var results = from c in _ServiceContext.StackUserTable
                          select c;

            var query = results.AsTableServiceQuery();
            var queryResults = query.Execute();

            return queryResults;
        }
        catch (MyExternalExceptionHelperDLL e)
        {
            // all exceptions referenced in MyExternalHelper are passed below
            MyExternalExceptionHelper.ProcessException(e);
         }
         catch (exception)
        {
         }

因为 MyExternalExceptionHelperDLL 可能无法动态选择要侦听的内容(即 SQL、网络、文件,但不是身份验证)

        try
        {
            var results = from c in _ServiceContext.StackUserTable
                          select c;

            var query = results.AsTableServiceQuery();
            var queryResults = query.Execute();

            return queryResults;
        }
         catch (exception e)
        {
           MyExternalExceptionHelper.ProcessException(e);

           // The problem is that I don't know how to catch exceptions thrown from that static method above,
           // or how to override that exception handling...
        }

但是对于上面的代码,我不清楚最终用户如何选择或覆盖我的事件处理方法。

【问题讨论】:

  • 您可以像在其他任何地方一样在 catch 块中调用辅助方法...
  • 长的switch 语句什么都不做是有原因的吗?
  • 谢谢@mellamokb,我刚刚更新了问题...

标签: c# exception dll stack stack-trace


【解决方案1】:

你可以做这样的事情。重要的部分是 throw 需要在原始的 catch 块中才能保留堆栈跟踪。

public IEnumerable<StackUserDataModel> Select() 
{
    try
    {
        ...
    }
    catch (StorageClientException e)
    {
       // You could do this if there is no fancy processing to do
       if (!IsCatchableException(e))
          throw;
    }
}

bool IsCatchableException(StorageClientException e)
{
    ... optionally do some fancy processing of the exception, e.g. logging....
    switch (e.ErrorCode)
    {
        case StorageErrorCode.AccessDenied:
        case StorageErrorCode.AccountNotFound:
        ....
        return true;
    }
}

【讨论】:

  • 我希望我的类的消费者覆盖我的异常处理。在catch (Exception e) 部分中调用IsCatchableException 是否明智,然后让我的应用程序确定异常是否适用于它?想法是用户始终可以实现catch (SpecialException abc),而我的代码永远不会看到。
【解决方案2】:

您只能在catch 子句中直接调用throw;,而throw e; 可以在您有异常实例e 的任何位置调用。它们之间的区别在于throw; 重新抛出异常,同时保持其原始堆栈跟踪不变,而throw e; 重置堆栈跟踪,以便看起来异常最初是由throw e; 引发的——这在调试时可能会很烦人.所以我建议您将switch 语句提取到一个单独的方法中,该方法以StorageClientException 作为参数,但将throw; 直接保留在catch 子句中。

【讨论】:

  • 那么ProcessException(e); 的正确实现是否会返回一个布尔值,并且抛出发生在那个确切的方法中,而不是我的 DLL?
猜你喜欢
  • 2017-06-12
  • 1970-01-01
  • 2021-03-17
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
相关资源
最近更新 更多