2012-03-18 62 views
3

thread resolved yesterday中,@hvd向我展示了如何在处理未知类型的代表时处理通过.Invoke进行的异常处理的“控制”(类似Isis2这样的库中出现的问题,最终用户提供多态事件处理程序和库类型匹配以决定要调用哪一个)。 HVD的建议围绕着知道upcall处理程序接收到多少个参数,然后使用该信息构建正确类型的泛型,从而允许构建动态对象并调用它。序列完全控制异常处理。动态调用中受控异常处理,具有可变数量的参数

他的建议的核心是Isis2可能会考虑做向上调用这种方式:

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); 

我的问题是:任何人都可以提出一个方法来做到这一点的论点任意数量的工作原理是一回事吗?很明显,我可以做一个switch语句并为1 arg,2等编写代码。但是有没有办法在mi.GetParameters().length的长度告诉我们有多少个参数?

作为不想单击链接的人的胶囊摘要,核心问题是:当进行这些动态上调时,最终用户(注册被调用方法的人)可能会抛出异常由于错误。事实证明,当不在Visual Studio下运行时(当直接在CLR中运行时),C#.Invoke将捕获并重新引发异常,将它们作为内部异常打包到InvocationTargetException中。这展开了堆栈并导致用户认为该错误是因为调用(例如,使用MY代码)的代码而导致的某种问题。这就是为什么C#参考手册认为catch/rethrow是糟糕的编码习惯:一个应该只捕获一个计划处理的异常...

hvd解释说,这基本上是因为.Invoke没有关于数字的线索或参数的类型,并且在那种模式下,显然,由于某种原因捕捉和重新抛出异常。他的解决方法主要是查看参数的数量(在该示例中为泛型:Action <,>),这显然足以使.Invoke不会执行“通用捕获”。但是要使用他的例子来实现任意代码,我需要每种可能的参数数量。可行(毕竟,谁会想要超过16?),但丑陋!

因此,今天的挑战:改进代码,以便使用C#的类似3行代码片段,无论有多少个参数,它都能正常工作。当然,由此产生的委托也需要被调用,大概是一个对象矢量,每个参数一个...

PS:悲观主义的一个原因:操作本身有16种形式,有1到16个参数。所以对我来说,这表明C#开发人员没有看到更通用的方式来做到这一点,并最终得到了使用switch语句对应于我的版本(我想交换机会有0到16个参数的情况,因为我需要一个动作< ...>带有N型参数来处理N个用户提供的参数!)

+1

你为什么要尽力避免DynamicInvoke()'的行为?捕捉和重新抛出异常是.Net中的一种常见做法。在调查异常时,您应该始终查看'InnerException',我期望您的库的用户可以完全做到这一点。为什么这对你来说是一个巨大的问题? – svick 2012-03-18 15:20:38

+0

@svick,问题是如果提供事件处理程序的最终用户具有复杂的逻辑,并且该代码会引发异常,则捕获并重新抛出异常会展开堆栈,并且我们会失去调试问题所需的大部分上下文 - - 当然,我们知道在哪一行发生空引用(因为这是内部异常的一部分),但我们不知道哪些变量具有什么值,调用堆栈上的方法的参数是什么(我们知道谁所谓的什么,什么行,但没有更多)等等。所以当catch/rethrow发生时,很多有用的数据会丢失 – 2012-03-18 15:29:33

+0

typeof(Program).GetMethod(“Foo”,BindingFlags.Static | BindingFlags .NonPublic,null,args.Select(x => x.GetType())。ToArray(),null).Invoke(null,args);'? – 2012-03-18 15:30:16

回答

0

我不想让它永远打开,所以我已经做了我能理解的东西核心问题,包括下载Mono中的.Invoke代码。据我所知,最初的问题仅仅是由于优化有利于更快的调用,这是以一种动态Invoke在具有参数向量的对象上完成时捕获异常的代价。使用通用模板创建的动态代理的代码根本就没有这个功能。

不是一个好的答案,但没有访问Invoke的.NET实现,它显然不可能提供更好的答案。

相关问题