Controlled Exception Handling in Dynamic Calls with Variable Number of Parameters

In a thread resolved yesterday , @hvd showed me how to get "control" of .Invoke exception handling when dealing with delegates of unknown type (the problem is seen in libraries like Isis2 where the end user exposes polymorphic event handlers and the type of library type to decide for a call). Hvd's proposal revolved around knowing how many arguments the upcall handler received and then using that information to build a generic type of the correct type, which allowed it to build a dynamic object and call it. Consistency provided complete control over exception handling.

The core of his suggestion was that Isis2 might think about doing upcalls this way:

MethodInfo mi = typeof(Program).GetMethod("Foo", BindingFlags.Static | BindingFlags.NonPublic); 
Delegate del = Delegate.CreateDelegate(typeof(Action<,>).MakeGenericType(mi.GetParameters().Select(p => p.ParameterType).ToArray()), mi);
((dynamic)del).Invoke(arg0, arg1);

      

Here's my question: can anyone suggest a way to do the same that works for an arbitrary number of arguments? Clearly I can make a switch statement and write code for case 1 arg, 2, etc. But is there any way to do it where mi.GetParameters (). Length tells us how many arguments?

As a summary of the capsules for those who don't want to click on the link, the main problem is this: when doing these kinds of dynamic promotions, the end user (who registered the method being called) can throw an exception due to errors. It turns out that when launched in Visual Studio - when launched directly in the CLR - C # .Invoke will catch and discard exceptions, wrapping them as internal exceptions inside an InvocationTargetException. This expands the stack and makes the user perceive the error as having some kind of problem with the code that caused .Invoke (for example, MY code). This is why the C # reference manual states that catch / rethrow is bad coding practice: you only need to catch the exceptions you plan to handle ...

hvd explained that this was mainly because .Invoke had no idea about the number or types of arguments and in this mode, it seems to be catching and retelling exceptions for some reason. His workaround essentially reduces the number of arguments (common in the example: Action <,>), and this seems to be enough to prevent .Invoke from doing a "universal catch". But to use his example for arbitrary code, I need a case for every possible number of parameters. A treat (after all, who wants more than 16?) But ugly!

So the challenge today is to improve this code so that it works with a similar 3-line C # snippet no matter how many parameters. Of course, the resulting delegate must also be called, presumably with a vector of objects, one per argument ...

PS: One of the reasons for pessimism: the action itself takes place in 16 forms with 1 to 16 arguments. So for me it says that the C # devs didn't see a more general way to do this and ended up with a version that matched me with a switch statement (and I think the switch would have cases 0 to 16 arguments, so how would I need an Action <...> argument with N type to handle N user supplied arguments!)

+3


source to share


1 answer


I don't want to leave this open forever, so I did everything I could to figure out the underlying problem, including loading the code for .Invoke into Mono. As far as I can tell, the original problem is simply due to an optimization that makes calls faster by throwing exceptions in such a way when a dynamic Invoke is executed on an object with a vector of arguments. The dynamic delegate code generated using the generic template simply doesn't have that catch in it.



Not a great answer, but no access to the Invoke.NET implementation. It seems impossible to give a better option.

0


source







All Articles