Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Method name that threw exception

Tags:

c#

exception

I know. A similar question has already asked.

  • How to get the name of the method that caused the exception

but I haven't got the exact solution from that.

I have a button click event in which I have a method FillCombo().

Button Click event

private void button1_Click(object sender, EventArgs e)
{
      try
      {
          cmbTemplates.Items.Clear();
          lstFiles.Clear();
          FillCombo();                
      }
      catch (Exception ex)
      {
           MethodBase site = ex.TargetSite;
           Log(ex.ToString(), site == null ? null : site.Name);                
      }
}

When I debugged, I found that the exception occurs from FillCombo() method. After that I get the value of site.Name as WinIOError instead of FillCombo.

I tried another method GetExecutingMethodName() which was answered by Chris Gessler in How to get the name of the method that caused the exception question. So I tried sending the name of method that caused exception using GetExecutingMethodName() method

Log(ex.ToString(), GetExecutingMethodName());

But I got the result as System.Windows.Forms.Control.OnClick instead of FillCombo.

How do I get the actual name of method that caused exception?

like image 637
Sarath KS Avatar asked Jan 17 '15 07:01

Sarath KS


People also ask

How to define methods that throw exceptions?

The throws keyword is used to declare which exceptions can be thrown from a method, while the throw keyword is used to explicitly throw an exception within a method or block of code. The throws keyword is used in a method signature and declares which exceptions can be thrown from a method.

How to catch exception thrown by another method in java?

The caller has to handle the exception using a try-catch block or propagate the exception. We can throw either checked or unchecked exceptions. The throws keyword allows the compiler to help you write code that handles this type of error, but it does not prevent the abnormal termination of the program.

Does php have try-catch?

The primary method of handling exceptions in PHP is the try-catch. In a nutshell, the try-catch is a code block that can be used to deal with thrown exceptions without interrupting program execution. In other words, you can "try" to execute a block of code, and "catch" any PHP exceptions that are thrown.


3 Answers

.net supports getting the stack trace information from an exception. You could filter out the method (and its name) by examining the first frame (origin).

new StackTrace(ex).GetFrame(0).GetMethod().Name

This would probably give you exactly the same as the targetsite (the win io), but you can examine the stacktrace for the first user code, or the first frame in your type, or whichever your needs.

For example, getting the name of the culprit thrower in your current assembly:

var s = new StackTrace(ex);
var thisasm = Assembly.GetExecutingAssembly();                
var methodname = s.GetFrames().Select(f => f.GetMethod()).First(m => m.Module.Assembly == thisasm).Name;
like image 193
Me.Name Avatar answered Oct 17 '22 13:10

Me.Name


It is important to understand what is meant by "the method that threw the exception". When an exception occurs, there is a specific method that is actually executing. Just because at some point before the exception, you called your own FillCombo() method, that doesn't mean that's the method that threw the exception.

The FillCombo() method will however (in the case you care about here) be in the stack trace. That's why it's useful to log the entire stack trace. Indeed, I just generally log the whole Exception object (i.e. ex.ToString(), or just pass the exception object to string.Format() or similar which will call ToString() for you). This will include the exception type, the message, the entire stack trace, and even inner exception information if present.


The code you got from the other question, for the GetExecutingMethodName() method, is not really all that useful IMHO. You'll note that what it really does is crawl through the stack trace of the current executing location, looking for the first method that is declared in a type other than the one where the GetExecutingMethodName() was declared.

This is wrong for your purpose for two reasons:

  1. It appears you've declared that method in the same class where your Click event handler is declared. This means the event handler method is ignored, and so you get the caller of that method, which is the Control.OnClick() method (i.e. the method that actually raises the event).

Frankly, I find that particular answer odd, because .NET already provides an API for retrieving the MethodInfo of the currently executing method: MethodBase.GetCurrentMethod. And this is way more reliable than the code Chris Gessler wrote.

  1. More problematic, you don't have an opportunity to call this method at the point where the exception is thrown! At best (i.e. even if you deal with the question of where the helper method is declared), all that calling that will tell you is that you are in your button1_Click() method. But you already know that, because the code you're writing to handle the exception is in that method.


If you want to know the name of the method in your currently executing method that was called before the exception occurred, you can combine the two techniques: get the name of the currently executing method, and then pass that to a method that takes both that and the stack trace string from the Exception object, and let that method parse the stack trace string to find the frame just before the currently executing method in the trace.

It's a bit of a pain, but it could be done. Here's an example of what that would look like (simple proof-of-concept console program):

static void Main(string[] args)
{
    try
    {
        CallForException();
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception occurred calling {0} method", GetCallForExceptionThisMethod(MethodBase.GetCurrentMethod(), e));
    }
}

private static string GetCallForExceptionThisMethod(MethodBase methodBase, Exception e)
{
    StackTrace trace = new StackTrace(e);
    StackFrame previousFrame = null;

    foreach (StackFrame frame in trace.GetFrames())
    {
        if (frame.GetMethod() == methodBase)
        {
            break;
        }

        previousFrame = frame;
    }

    return previousFrame != null ? previousFrame.GetMethod().Name : null;
}

private static void CallForException()
{
    DoActualException();
}

private static void DoActualException()
{
    throw new NotImplementedException();
}

Finally, keep in mind that due to method inlining and other optimizations, even a full stack trace may have some irregularities in it, including not even having the actual name of the method where the exception was thrown. That's another reason that logging the entire Exception object is usually much more useful; the more context, the more likely you are to be able to reconstruct what happened.

like image 11
Peter Duniho Avatar answered Oct 17 '22 14:10

Peter Duniho


Just try this:

var methodFullName = exception.TargetSite.ReflectedType.FullName 
like image 4
Ankit Avatar answered Oct 17 '22 12:10

Ankit