简体   繁体   中英

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

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 . 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 :

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.

An ugly/unmaintainable/unruly solution would be to use status variables and you check for in the catch block.

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

xExceptionObj.TargetSite.Name

output will be "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"]

The alternative is a class XWrapper : Exception where you can add your own properties, and then replace the throw; with throw new XWrapper(..., ex); And of course you then have to catch(Xwrapper xObj) ... outside the loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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