不同方法抛出相同异常如何捕获?

3
请看下面的代码,其中两个方法抛出了相同类型的异常,但上下文完全不同。
class Test
{
 public void methodThrowingExceptionX()
 {
   //some code
   throw new X();
 }

 public void anotherMethodThrowingExceptionX()
 {
   //some code
   throw new X();  
 }
}
class TestClient
{
  private Test testObj = new Test();
  public Response TestMethodCaller() 
  {
    try
    {
       testObj.methodThrowingExceptionX();
       testObj.anotherMethodThrowingExceptionX();
    }

    catch(X xExceptionObj)
    {
      //this will catch X exception regardless from which method it is comming
      //How can i distinguish from where the exception is coming(which method is throwing)
      //so that i can return the Response object according to the context of the method which has thrown this exception?
    }
  }
}

我遇到了一个问题,使用上述的catch会捕获两个方法中类型为X的异常。但是我的高级逻辑要求在不同的方法中产生X异常时有不同的Response对象(例如,具有不同的语言代码、不同的消息和不同的应用程序特定代码)。或者可以说,Response应根据上下文而变化。

如何最好地实现这一点?

编辑

以下代码告诉您我为什么要这样做

interface ICommand
{
    void execute();
}

//say we have some command implementation
class CommandA : ICommand 
{
  public void execute()
  {

    //some code 
    throw new X();
  }

}

class CommandB : ICommand 
{
  public void execute()
  {

    //some code 
    throw new X();
  }

}
class MacroCommand : ICommand
{
    List<ICommand> commands;

    public MacroCommand(List<ICommand> commands)
    {
        this.commands = commands;

    }
    public void execute()
    {
       foreach(ICommand command in commands)
       {

           //execute method of various commands can throw exceptions may of     same type say X.
           command.execute();
       }
    }
}

class Client
{

   List<ICommand> commands = new List<ICommand>();

   commands.Add(new CommandB());
   commands.Add(new CommandA());

   MacroCommand macroCommand = new MacroCommand(commands);

   try
   {

        macroCommand.execute();
   }

   catch(X xExceptionObj)
   {
     //How can i get the information which execute() actually thrown the exception??

   }

}

1
将每个方法调用都包裹在 try...catch 中,这样你就知道它来自哪里了 ;) - Tim Schmelter
@TimSchmelter,实际上我正在实现命令模式,并且有一个宏命令,在其中我有一系列命令对象。在这种情况下,我对列表进行foreach操作,以调用列表中每个对象上的相同方法,因此我无法在每个方法调用上单独进行try catch处理。 - OldSchool
那么问题就在于foreach()和你的“不同响应”要求之间。不要怪可怜的异常。 - H H
4个回答

5
正常的方式是将两个方法调用都包含在它们自己的 try...catch 中。这样你总是知道是什么引起了异常,并且你可以单独处理它。
如果出于任何原因你想避免这种情况,你可以使用 Exception.TargetSite
try
{
    testObj.methodThrowingExceptionX();
    testObj.anotherMethodThrowingExceptionX();
}
catch (X xExceptionObj)
{
    MethodBase site = xExceptionObj.TargetSite;

    switch (site.Name)
    {
        case nameof(testObj.methodThrowingExceptionX):
            return blah....
        case nameof(testObj.anotherMethodThrowingExceptionX):
            return blub....
        default:
            throw new Exception("Unexpected method caused exception: " + site.Name);
    }
}

我正在编辑答案,以便更清楚地表达我的意思,请看一下。 - OldSchool
@Rouftantical:仍不清楚您为何无法使用我的方法来确定引发异常的方法。除此之外,您的异常 X 应包含您需要了解的必要细节作为属性。 - Tim Schmelter
不必使用反射,只需使用 ex.Source 属性将其设置为方法名称,然后将其与方法名称进行比较即可。 - OldSchool
@Rouftantical:Source 属性会给出异常发生的应用程序名称。 - Tim Schmelter

1
唯一干净的方法是使用2个try..catch块,每个调用周围都有一个。
丑陋/难以维护/难以管理的解决方案是使用状态变量,并在catch块中检查。

但我想避免那个 :( - OldSchool
异常过滤器和异常中的属性应该也能在VS 2015上工作。 - Mark
2
为什么你想要避免那样做?如果知道异常抛出的位置很关键,你必须分别尝试捕获两个方法调用。 - Tim Schmelter
@TimSchmelter 请查看您答案中的评论。 - OldSchool

1
有两种方法可以实现这个,一种是使用xExceptionObj.StackTrace,它包含了完整的调用层次结构,因此你可以从中搜索所需的详细信息。如果多个父级调用相同的方法并且您想将其作为基类的一部分处理,则应优先考虑此方法。

enter image description here

对于您的简单情况,我更喜欢使用TargetSite对象,这是一种简单易懂的方法。

xExceptionObj.TargetSite.Name

输出将是"methodThrowingExceptionX" 这里输入图片描述

1

编辑完成后,

在宏执行中,您有机会丰富或封装异常:

public void execute()
{
   foreach(ICommand command in commands)       
   {
       try
       {
         command.execute();
       }
       catch(X ex)
       {
          // add one or more command related pieces of info to the exception
          ex.Data.Add("Command", command.Name);
          throw;
       }
   }
}

然后,当您在更高层次处理异常时,您可以从ex.Data["Command"]中获取您的ICommand。

另一种选择是使用class XWrapper : Exception,您可以添加自己的属性,然后用throw new XWrapper(..., ex);替换throw;。当然,在循环外部需要catch(Xwrapper xObj) ...


在编译时,它会报错:无法将[]索引运算符应用于类型为Exception的表达式。 - OldSchool
现在它会抛出运行时异常,说“传递的参数不可序列化”,当您执行ex.Data.Add("Command", command)时? :( - OldSchool
这并没有真正回答我的问题。'where'总是在foreach的相同位置。如何从ICommand获取所需的响应? - H H
让我们在聊天室中继续这个讨论 - OldSchool
默认情况下,源代码中包含项目名称,但我认为这没有什么用处,所以我将其删除了。不过,如果需要,我也可以将其放入数据中,没有问题。 - OldSchool
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接