MethodInfo.Invoke throws unexpected exception - c#

Im trying to make a custom shell.
public static void CallMethod(string method, string[] args)
{
try
{
Type type = typeof(Program);
MethodInfo methodInfo = type.GetMethod(method);
methodInfo.Invoke(method, args);
}
catch(TargetException)
{
Console.WriteLine("The method + '" + method + "' does not exist.");
}
catch(TargetParameterCountException)
{
Console.WriteLine("The parameter count for '" + method +"' does not fit.");
}
catch(Exception)
{
Console.WriteLine("An unexpected error occured.");
}
}
I am expecting TargetException to be thrown when the method-string doesnt contain an existing method - like the MS documentation says. But in this case the Exception is thrown. Little example: There is no function example(), so it should throw TargetException when method contains "example", but it seems that another Exception is thrown
My question ist what exception is thrown in this specific case?

Related

Trying to catch a FormatException error fails. Only Exception can catch it?

I have a method that accepts random data at runtime (it could be string, int, etc.) and then it tries adding this data to a list of a random type (e.g. List<byte>, List<int>, etc.).
Due to the unpredictable nature of this, I have added 2 error handling routines. One to catch a FormatException error and do some specific actions to fix the data. And secondly, I've also added a general catch-all for Exception so if another error I'm not expecting is thrown, I can display the details and exit the application gracefully.
The weird issue I'm having (or at least it seems weird to me), is that whenever a FormatException error is thrown, my Catch (FormatException ex) does nothing and instead the error is being caught by Catch (Exception ex). So rather than being able to handle the error properly, the application exits instead.
To help isolate this, I've created a small example C# WinForms program that replicates the issue.
Here's the main form code:
private void button1_Click(object sender, EventArgs e)
{
// This works normally
ErrorClass.TestCatchFormatException<string, string>("abc", "def");
// This also works normally
ErrorClass.TestCatchFormatException<int, int>("123", "456");
// This should raise a FormatException error but only Exception catches it???
ErrorClass.TestCatchFormatException<int, string>("abc", "456");
}
And here's the code for my 2 classes:
public class DataClass<T, U>
{
public T Data1 { get; set; }
public U Data2 { get; set; }
}
public static class ErrorClass
{
public static void TestCatchFormatException<T, U>(dynamic inputString, dynamic inputString2)
where T : IComparable<T>
where U : IComparable<U>
{
try
{
List<DataClass<T, U>> theList = new List<DataClass<T, U>>();
TypeConverter converter1 = TypeDescriptor.GetConverter(typeof(T));
TypeConverter converter2 = TypeDescriptor.GetConverter(typeof(U));
theList.Add(new DataClass<T, U>
{
Data1 = converter1.ConvertFrom(inputString.ToString()),
Data2 = converter2.ConvertFrom(inputString2.ToString())
});
MessageBox.Show(
"Data1 Value is: " + theList[0].Data1.ToString() + "\n"
+ "Data1 Type is: " + theList[0].Data1.GetType().ToString() + "\n"
+ "Data2 Value is: " + theList[0].Data2.ToString() + "\n"
+ "Data2 Type is: " + theList[0].Data2.GetType().ToString());
}
catch (FormatException ex)
{
// Catches nothing for some reason
MessageBox.Show("Caught FormatException\n\n" + ex.Message + "\n\n" + ex.InnerException);
}
catch (Exception ex)
{
// This catches the error but InnerException says the error is of type FormatException.
// Yet FormatException doesn't catch it???
MessageBox.Show("Caught Exception\n\n" + ex.Message + "\n\n" + ex.InnerException);
}
}
}
Even weirder is that when I look at the InnerException the catch-all Exception generates, it says this:
System.FormatException: Input string was not in a correct format.
So it is detecting it as a FormatException error. Yet for some reason, catching FormatException does nothing and only Exception can catch it.
Does anyone know what I'm doing wrong here?
Your FormatException is being wrapped in some other Exception type. That's why the .InnerException property has a FormatException. Try calling .GetType on the exception you are getting to see the wrapping type, and catch that instead.
BaseNumberConverter.ConvertFrom() internally calls a helper function to throw an exception:
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
...
catch (Exception e) {
throw FromStringError(text, e);
}
}
return base.ConvertFrom(context, culture, value);
}
The implementation of FromStringError is:
internal virtual Exception FromStringError(string failedText, Exception innerException) {
return new Exception(SR.GetString(SR.ConvertInvalidPrimitive, failedText, TargetType.Name), innerException);
}
So it throws an Exception that wraps the actual FormatException and adds some additional information (namely the value it's trying to convert and the type it's trying to convert to). Why it doesn't throw another FormatException I don't know.
Prior to C# 6 there was no way to create a catch that would catch based on the InnerException. You'd have to catch Exception and inspect the InnerException type to handle it differently.
With C# 6 you can use an exception filter:
catch (Exception ex) when (ex.InnerExcpetion is FormatException)
{
// Catches nothing for some reason
MessageBox.Show("Caught FormatException\n\n" + ex.Message + "\n\n" + ex.InnerException);
}
catch (Exception ex)
{
// This catches the error but InnerException says the error is of type FormatException.
// Yet FormatException doesn't catch it???
MessageBox.Show("Caught Exception\n\n" + ex.Message + "\n\n" + ex.InnerException);
}

Get exception method name [duplicate]

My code looks as below.
try
{
_productRepo.GetAllProductCategories();
}
catch (Exception ex)
{
//Do Something
}
I need a way to show the method name, suppose in the above case if any exception is thrown in the GetAllProductCategories() method, I need to get this method name i.e. "GetAllProductCategories()" as my result. Can any one suggest me how to do this?
There's a TargetSite property on System.Exception that should come in handy.
Gets the method that throws the
current exception.
In your case, you probably want something like:
catch (Exception ex)
{
MethodBase site = ex.TargetSite;
string methodName = site == null ? null : site.Name;
...
}
It's worth pointing out some of the issues listed:
If the method that throws this
exception is not available and the
stack trace is not a null reference
(Nothing in Visual Basic), TargetSite
obtains the method from the stack
trace. If the stack trace is a null
reference, TargetSite also returns a
null reference.
Note: The TargetSite property may not
accurately report the name of the
method in which an exception was
thrown if the exception handler
handles an exception across
application domain boundaries.
You could use the StackTrace property as #leppie suggests too, but do note that this is a string representation of the frames on the stack; so you'll have to manipulate if you only want the name of the method that threw the execption.
It's in the StackFrame...
private string GetExecutingMethodName()
{
string result = "Unknown";
StackTrace trace = new StackTrace(false);
Type type = this.GetType();
for (int index = 0; index < trace.FrameCount; ++index)
{
StackFrame frame = trace.GetFrame(index);
MethodBase method = frame.GetMethod();
if (method.DeclaringType != type && !type.IsAssignableFrom(method.DeclaringType))
{
result = string.Concat(method.DeclaringType.FullName, ".", method.Name);
break;
}
}
return result;
}
This method was written for an Logging handler class and the use of GetType() simply eliminates the methods within the Logging handler class from being returned as the last executing method. Since the Logging handler class was written for more than just logging exceptions, a new StackTrace object was required. Obviously, for finding "the method that threw the exception" GetType() might not be necessary.
If you just want the top of the stack, take the first frame, call GetMethod() and return that, or simply use TargetSite. GetType() could then be removed. Also note, that the Exception would need to be passed in to create the StackTrace object. For example:
class Program
{
static void Main(string[] args)
{
try
{
Test();
}
catch (Exception ex)
{
// does not work properly - writes "Main"
Console.WriteLine(MethodBase.GetCurrentMethod());
// properly writes "TestConsole.Program.Test"
Console.WriteLine(GetExecutingMethodName(ex));
// properly writes "Test"
Console.WriteLine(ex.TargetSite.Name);
}
Console.ReadKey();
}
static void Test()
{
throw new Exception("test");
}
private static string GetExecutingMethodName(Exception exception)
{
var trace = new StackTrace(exception);
var frame = trace.GetFrame(0);
var method = frame.GetMethod();
return string.Concat(method.DeclaringType.FullName, ".", method.Name);
}
}
Basically, if TargetSite() does what you want, then go no further. But, often times in Logging handlers, an exception object is not available (i.e. tracing and auditing) so a new StackTrace() object is necessary for retrieving the last executed method, the one BEFORE the Logging method.
Look at the stacktrace.
It's a property on the exception.

Is a generic exception supported inside a catch?

The above block refering to another question+answer on SO does NOT contain a correct answer which applies here!
I have a method used for unit testing. The purpose of this method is to ensure that a piece of code (refered to by a delegate) will throw a specific exception. If that exception is thrown, the unit test succeeds. If no exception is thrown or another type exception is thrown, the unit test will fail.
/// <summary>
/// Checks to make sure that the action throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="action">The code to execute which is expected to generate the exception.</param>
public static void Throws<TException>(Action action)
where TException : Exception
{
try
{
action();
}
catch (TException)
{
return;
}
catch (Exception ex)
{
Assert.Fail("Wrong exception was thrown. Exception of type " + ex.GetType() + " was thrown, exception of type " + typeof(TException) + " was expected.");
}
Assert.Fail("No exception was thrown. Exception of type " + typeof(TException) + " was expected.");
}
The next call should succeed, but it fails:
int result = 0;
Throws<DivideByZeroException>(() => result = result / result);
When the expected exception of type TException is thrown, it is always caught by the second catch, not by the first catch. Why is this?
Of course I can use a workarround with one catch and test if ex is of type TException. By I simply want to know/understand why this code compiles but simple (never?) works.
EDIT
At request a "working" demo:
using System;
namespace GenericExceptionDemo
{
class Program
{
static void Main(string[] args)
{
int n = 0;
Catch<DivideByZeroException>(() => n = n / n);
}
static public void Catch<TException>(Action action)
where TException: Exception
{
try
{
action();
Console.WriteLine("No exception thrown. !!!Fail!!!");
}
catch (TException)
{
Console.WriteLine("Expected exception thrown. PASS!");
}
catch(Exception ex)
{
Console.WriteLine("An unexpected exception of type " + ex.GetType() + " thrown. !!!FAIL!!!");
}
}
}
}
You're not the first person to encounter this problem. This question is very similar. If you dig through the answers and links, it comes down to a bug in the CLR.
EDIT:
As a follow up, I've run Martin's example from VS2010 and got the following results:
Targetting .NET 4, PASS
Targetting .NET 3.5, FAIL
Targetting .NET 3.5 in RELEASE mode, PASS
Sadly, all the SO links to the Microsoft Bug Report are dead now and I haven't been able to find any others.
(This is not a concrete answer; but I could not post it as a comment too.)
I can not reproduce this (VS 2012, .NET 4.5, C# 5.0, every SP installed).
I defined this exception class:
class MyException : Exception
{
public MyException() { }
public MyException(string message) : base(message) { }
}
and a method:
static void Throws<T>(Action action) where T : Exception
{
try
{
action();
}
catch (T) { Console.WriteLine("got {0}", typeof(T)); }
catch (Exception) { Console.WriteLine("got Exception"); }
}
and I have tested it this way:
Throws<MyException>(() => { throw new MyException(); });
int result = 0;
Throws<DivideByZeroException>(() => result = result / result);
and the output is:
got Draft.MyException
got System.DivideByZeroException
So (IMHO) you should look somewhere else.

Puzzle involving unwound stacks on dynamic invoke

This is a new attempt to pose a version of a question asked less successfully this morning.
Consider the following program, which we'll run once inside Visual Studio 2010 and once more by double-clicking the executable directly
namespace ConsoleApplication3
{
delegate void myFoo(int i, string s);
class Program
{
static void Main(string[] args)
{
Foo(1, "hello");
Delegate Food = (myFoo)Foo;
Food.DynamicInvoke(new object[] { 2, null });
}
static void Foo(int i, string s)
{
Console.WriteLine("If the next line triggers an exception, the stack will be unwound up to the .Invoke");
Console.WriteLine("i=" + i + ", s.Length = " + s.Length);
}
}
}
When the exception in Foo triggers while running VS, the debugger shows the stack correctly and shows that the problem occured on the second WriteLine in Foo.
But when the exception occurs while running the executable directly, one gets a little popup window from the CLR indicating that the program threw an unhandled exception. Click debug and select the VS debugger. In this case, the stack unwinds up to the point of the most recent .DynamicInvoke and when you attach with the debugger, the stack context that existed at the time of the exception has been partially lost.
It does exist, in a limited form, within the "inner exception" portion of the exception event. You click to expand the associated information and find the line number where the problem occured. But obviously local variables and other context will be gone.
If one tries the same thing but without the .DynamicInvoke (for example, call Foo(1, null) on line 1 of Main), still by double-clicking the .exe file, we DO get the correct line number when the debugger attaches. Similarly if the application is launched by clicking on the .exe, but then the debugger is attached before the exception gets thrown.
Does anyone know how an application using dynamic reflection/invocation could avoid this problem? In my intended use case, in a system the name of which I won't mention here, I cannot predict the type signature of the object that will be used in the .DynamicInvoke, or even the number of arguments that will be employed, hence static typing or even generics aren't a way out of this.
My question is this: does anyone know why we get such different behaviors when running directly from the debugger versus when attaching to the program after the exception is thrown?
As per the comments, whether you see the NullReferenceException as unhandled depends on whether it's handled. Here are some ways to call Foo, the first three will leave the exception as unhandled, the last two will handle the NullReferenceException by wrapping it, and throwing a new exception.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApplication3
{
delegate void myFoo(int i, string s);
internal class Program
{
private static void Main(string[] args)
{
Foo(1, "hello");
// From a delegate
try
{
Delegate Food = (myFoo)Foo;
((dynamic)Food).Invoke(2, null);
}
catch (NullReferenceException ex)
{ Console.WriteLine("Caught NullReferenceException at " + ex.StackTrace); }
MethodInfo Foom = typeof(Program).GetMethod("Foo", BindingFlags.Static | BindingFlags.NonPublic);
// From a MethodInfo, obtaining a delegate from it
try
{
Delegate Food = Delegate.CreateDelegate(typeof(Action<,>).MakeGenericType(Foom.GetParameters().Select(p => p.ParameterType).ToArray()), Foom);
((dynamic)Food).Invoke(2, null);
}
catch (NullReferenceException ex)
{ Console.WriteLine("Caught NullReferenceException at " + ex.StackTrace); }
// From a MethodInfo, creating a plain Action
try
{
Expression.Lambda<Action>(
Expression.Call(
Foom,
Expression.Constant(2),
Expression.Constant(null, typeof(string)))).Compile()();
}
catch (NullReferenceException ex)
{ Console.WriteLine("Caught NullReferenceException at " + ex.StackTrace); }
// MethodBase.Invoke, exception gets wrapped
try
{
Foom.Invoke(null, new object[] { 2, null });
}
catch (NullReferenceException)
{ Console.WriteLine("Won't catch NullReferenceException"); }
catch (TargetInvocationException)
{ Console.WriteLine("Bad!"); }
// DynamicInvoke, exception gets wrapped
try
{
Delegate Food = (myFoo)Foo;
Food.DynamicInvoke(2, null);
}
catch (NullReferenceException)
{ Console.WriteLine("Won't catch NullReferenceException"); }
catch (TargetInvocationException)
{ Console.WriteLine("Bad!"); }
}
private static void Foo(int i, string s)
{
Console.WriteLine("i=" + i + ", s.Length = " + s.Length);
}
}
}
Actually answered by #hvd:
((dynamic)Food).Invoke(2, null);
solves my problem in one line of code. Thanks!

Catching exception types given as type parameters in C# 2.0

In the following method, the first catch block is never run, even when an exception of type ExceptionType is thrown:
/// <summary>
/// asserts that running the command given throws an exception.
/// </summary>
public static void Throws<ExceptionType>(ICommand cmd)
where ExceptionType : Exception
{
// Strangely, using 2 catch blocks on the code below makes the first catch block do nothing.
try
{
try
{
cmd.Execute();
}
catch (ExceptionType)
{
return;
}
}
catch (Exception f)
{
throw new AssertionException(cmd.ToString() + " threw an exception of type " + f.GetType() + ". Expected type was " + typeof(ExceptionType).Name + ".");
}
throw new AssertionException(cmd.ToString() + " failed to throw a " + typeof(ExceptionType).Name + ".");
}
as indicated by the following test:
[Test]
public void Test_Throws_CatchesSpecifiedException()
{
AssertThat.Throws<AssertionException>(
new FailureCommand()
);
}
using the following class:
class FailureCommand : ICommand
{
public object Execute()
{
Assert.Fail();
return null; // never reached.
}
public override string ToString()
{
return "FailureCommand";
}
}
giving the following output in NUnit:
TestUtil.Tests.AssertThatTests.Test_Throws_CatchesSpecifiedException:
FailureCommand threw an exception of type NUnit.Framework.AssertionException. Expected type was AssertionException.
I also tried using 2 catch blocks for 1 try block (instead of nesting a try/catch within an outer try), but got the same results.
Any ideas as to how to catch the exception specified as a type parameter in one catch block, but catch all other exceptions in the other?
Works fine for me in this test:
using System;
using System.IO;
class Test
{
static void Main()
{
Throws<ArgumentNullException>(() => File.OpenText(null));
}
public static void Throws<ExceptionType>(Action cmd)
where ExceptionType : Exception
{
try
{
try
{
cmd();
}
catch (ExceptionType)
{
Console.WriteLine("Caught!");
return;
}
}
catch (Exception f)
{
Console.WriteLine("Threw an exception of type " + f.GetType()
+ ". Expected type was " + typeof(ExceptionType) + ".");
}
Console.WriteLine("No exception thrown");
}
}
How certain are you that the two AssertionException exceptions are identical? Are they definitely in the same namespace (print typeof(ExceptionType) rather than just the Name property)? Are they from the same assembly? I wouldn't be surprised to find some oddities due to multiple test framework versions coexisting...
Try it with an exception other than AssertionException to make life simpler.
See this thread for more info:
Why can't I catch a generic exception in C#?
Seems to be a bug:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=362422&wa=wsignin1.0
I haven't debugged this code or looked at it too long but could it be that you first "return" statement is causing the code to HALT and leave the method. Therefore, the exception is "caught" or "handled" (however you look at it) and the outer try/catch block is never executed.
Are you trying to do this?
try
{
try
{
cmd.Execute();
}
catch (ExceptionType)
{
throw;
}
}
catch (Exception f)
{
throw new AssertionException(cmd.ToString() + " threw an exception of type " + f.GetType() + ". Expected type was " + typeof(ExceptionType).Name + ".");
}

Categories