简体   繁体   English

捕获不同方法引发的相同异常?

[英]Catching same exception thrown by different methods?

Have a look at the following code, where two methods throw same type of exception but have different context altogether. 看看下面的代码,其中两个方法抛出相同类型的异常但完全具有不同的上下文。

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?
    }
  }
}

Problem which I am having with above catch is that it catches exception of type X from both the methods. 其中我正在与上述具有问题catch是,它捕捉型的异常X从两种方法。 But my high level logic requires to have different Response objects (say, to have different language code, different message, different application specific code for exception cause) when X exception comes from different method or you can say that Responose should change according to the context. 但是,当X异常来自不同的方法时,我的高级逻辑需要具有不同的Response对象(例如,具有不同的语言代码,不同的消息,异常原因的不同应用程序特定代码),或者您可以说Responose应根据上下文进行更改。

What is the best way to achieve this? 实现这一目标的最佳方法是什么?

Edit 编辑

Following code tells you why i want to do this 以下代码告诉您我为什么要这样做

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??

   }

}

The normal way is to surround both method calls with their own try...catch . 通常的方法是使用自己的try...catch包围两个方法调用。 On that way you always know what caused the exception and you can handle it separately. 在这种情况下,您始终知道导致异常的原因,您可以单独处理它。

If you want to avoid that for whatever reason you could use the Exception.TargetSite : 如果你想避免这种不管什么原因,你可以使用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);
    }
}

The only clean way to achieve this is to have 2 try..catch blocks, one around each call. 实现这一目标的唯一简洁方法是有2个try..catch块,每个调用一个。

An ugly/unmaintainable/unruly solution would be to use status variables and you check for in the catch block. 一个丑陋/不可维护/不守规矩的解决方案是使用状态变量并在catch块中检查。

There are two ways for this, one is to use xExceptionObj.StackTrace which contains complete call hierarchy, so from that info you can search for required details. 有两种方法,一种是使用包含完整调用层次结构的xExceptionObj.StackTrace,因此可以从该信息中搜索所需的详细信息。 This is preferred in case if more than one parent is calling same method and you like to handle it part of base class. 如果多个父级调用相同的方法并且您希望将其作为基类的一部分处理,则首选此方法。

在此输入图像描述

And then the easy one which I prefer for you simple case is to use TargetSite Object 然后,我喜欢的简单案例就是使用TargetSite Object

xExceptionObj.TargetSite.Name

output will be "methodThrowingExceptionX" 输出将是"methodThrowingExceptionX" 在此输入图像描述

After the edit, 编辑完成后

In the macro execute you have the opportunity to enrich or encapsulate the exception: 在宏执行中,您有机会丰富或封装异常:

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;
       }
   }
}

And then when you handle the exception higher up, you can have your ICommand back from ex.Data["Command"] 然后当你处理更高的异常时,你可以从ex.Data["Command"]返回你的ICommand

The alternative is a class XWrapper : Exception where you can add your own properties, and then replace the throw; 另一种方法是class XWrapper : Exception ,你可以在其中添加自己的属性,然后替换throw; with throw new XWrapper(..., ex); throw new XWrapper(..., ex); And of course you then have to catch(Xwrapper xObj) ... outside the loop. 当然,你必须catch(Xwrapper xObj) ...在循环之外。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM