runtime: Add a way to opt out of TargetInvocationException wrapping on late-bound invokes.
Late-bound invokes through Reflection wrap exceptions thrown by the target in a TargetInvocationException
. In many cases, this behavior is not desired and counter-productive. For those who want the actual exception, it requires unwrapping the TargetInvocationException
to rethrow the inner exception and to retrieve the full call stack. The fact that every exception is “caught” hampers the normal debugging experience. It’d be useful to have a way to opt out of this wrapping.
We can do this without adding lots of new overloads by adding a new member to the BindingFlags
enum: BindingFlag.DoNotWrapExceptions
. Setting this bit would disable the wrapping behavior.
Here is a fiddle of the code sample included below: https://dotnetfiddle.net/o9qUht
public class Program
{
public static void Main()
{
try {
var bf = BindingFlags.Static |
BindingFlags.Public |
BindingFlags.InvokeMethod;
bf |= BindingFlags.DoNotWrapExceptions;
typeof(Program).InvokeMember("LateBoundTarget", bf, null, null, null);
} catch(TargetInvocationException e) {
Console.WriteLine("fail");
} catch(InvalidOperationException e) {
Console.WriteLine("success");
}
}
public static void LateBoundTarget() {
throw new InvalidOperationException();
}
}
Apis that would be affected:
public static class Activator
{
public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture);
public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes);
}
public class Type
{
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args);
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, CultureInfo culture);
public abstract object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters);
}
public class Assembly
{
public virtual object CreateInstance(string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes);
}
public abstract class ConstructorInfo : MethodBase
{
public abstract object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture);
}
public abstract class MethodBase : MemberInfo
{
public abstract object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture);
}
public abstract class PropertyInfo : MemberInfo
{
public abstract object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture);
public abstract void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture);
}
[EDIT] Added C# syntax highlight by @karelz
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 16 (10 by maintainers)
Commits related to this issue
- Add the enum value for BindingFlags.DoNotWrapExceptions (#4433) This was approved here. https://github.com/dotnet/corefx/issues/22866 This does not implement the feature, it just adds the memb... — committed to dotnet/corert by deleted user 7 years ago
- Implement BindingFlags.DoNotWrapExceptions on Project N (#4437) This was approved here. https://github.com/dotnet/corefx/issues/22866 Ok, this one actually makes the feature work. Turned out n... — committed to dotnet/corert by deleted user 7 years ago
- Support for not wrapping exceptions with TargetInvocationException. (#13767) * Support for not wrapping exceptions with TargetInvocationException. For dotnet/corefx#22866. * Respond to PR feedb... — committed to dotnet/coreclr by AustinWise 7 years ago
- Expose the recently approved Reflection apis in contracts (#23882) Fixes https://github.com/dotnet/corefx/issues/22866 Fixes https://github.com/dotnet/corefx/issues/16567 — committed to dotnet/corefx by deleted user 7 years ago
- Add BindingFlags.DoNotWrapExceptions (#7863) The original design review is here: dotnet/corefx#22866 . To summarize, this adds a new flag to `BindingFlags` called `DoNotWrapExceptions`. When this fla... — committed to mono/mono by AustinWise 6 years ago
Video
Looks good, the only suggestion is to rename
PassExceptions
toDoNotWrapExceptions
. The rationale being that specifying~PassExceptions
could be read as catch-all.That has nice didactic qualities too: Seeing
DoNotWrapExceptions
immediately teaches people that exceptions get wrapped!Cleaned up the proposal a bit and promoted to api-ready-for-review.
We can tackle the
CreateInstance<T>()
thing separately if this gets approved.Project N implementation is now merged.
CoreCLR implementation is still up for grabs. The exception wrapping seems to occur in various places in C++ code so this will require some C++ work.
FYI: The API review discussion was recorded - see https://youtu.be/VppFZYG-9cA?t=5527 (duration: 14 min)