Stephen Gross
Stephen Gross

Reputation: 5714

Why is custom exception changed to System.Exception when method invoked via method.invoke()?

I've written a custom exception AbortTestException, which is pretty simple:

class AbortTestException : Exception
{
    public AbortTestException(string message) 
        : base(message) { }
}

Then I have a function that will throw it:

class Foo
{
    public void Throws()
    {
        throw new AbortTestException("hi");
    }
}

And Throws() gets called via method reference:

class Program
{
    static void Main(string[] args)
    {
        Type myType = (typeof(Foo));
        var method = myType.GetMethod("Throws");
        try
        {
            method.Invoke(new Foo(), null);
        }
        catch (AbortTestException ex)
        {
            Console.WriteLine("AbortTestException");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception");
        }
    }
}

However, something weird happens. Even though Throws rises an AbortTestException, the catch(Exception) block gets used (instead of the catch(AbortTestException) block). I tried putting the "throw new AbortTestException("hi")" portion in the try block itself, and verified that the correct catch block is used.

Is there some reason an exception would be re-cast when emitted via MethodInfo.invoke()?

Upvotes: 1

Views: 483

Answers (3)

Jon Hanna
Jon Hanna

Reputation: 113242

Remember that catching Exception will match any exception that isn't caught by a more specific catch block before it:

    Type myType = (typeof(Foo));
    var method = myType.GetMethod("Throws");
    try
    {
        try
        {
            method.Invoke(new Foo(), null);
        }
        catch (AbortTestException ex)
        {
            Console.WriteLine("AbortTestException");
        }
        catch(TargetInvocationException tie)
        {
            throw tie.InnerException;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception");
        }
    }
    catch(AbortTestException ate)
    {
        Console.WriteLine("AbortTestException after re-throw from TargetInvocationException");
    }

Upvotes: 0

mfeingold
mfeingold

Reputation: 7154

Did you check the nested Exception? My guess the original exception (AbortTest...) is wrapped in a nested one. The nested Exception will be in the InnerException property of the one which is caught by your code

Upvotes: 0

cadrell0
cadrell0

Reputation: 17307

http://msdn.microsoft.com/en-us/library/4k9x6bc0.aspx

Per the MSDN a TargetInvocationException is thrown if the invoked method or constructor throws an exception.

Upvotes: 5

Related Questions