我们在调用反映的通用委托时遇到了一些奇怪的事情。在某些情况下,使用attuched debuger我们可以进行不可能的调用,而没有调试器我们无法捕获任何异常和应用程序快速失败。
以下是代码:
using System;
using System.Windows.Forms;
using System.Reflection;
namespace GenericDelegate
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate Class2 Delegate1();
private void button1_Click(object sender, EventArgs e)
{
MethodInfo mi = typeof (Class1<>).GetMethod("GetClass", BindingFlags.NonPublic | BindingFlags.Static);
if (mi != null)
{
Delegate1 del = (Delegate1) Delegate.CreateDelegate(typeof (Delegate1), mi);
MessageBox.Show("1");
try
{
del();
}
catch (Exception)
{
MessageBox.Show("No, I can`t catch it");
}
MessageBox.Show("2");
mi.Invoke(null, new object[] {});//It's Ok, we'll get exception here
MessageBox.Show("3");
}
}
class Class2
{
}
class Class1<T> : Class2
{
internal static Class2 GetClass()
{
Type type = typeof(T);
MessageBox.Show("Type name " + type.FullName +" Type: " + type + " Assembly " + type.Assembly);
return new Class1<T>();
}
}
}
}
有两个问题:
用例: 您为应用程序开发了类似插件系统的东西。您阅读外部程序集,找到某种类型的合适方法,然后执行它。我们忘记了我们需要检查的类型是否通用。在VS(和.net从2.0到4.0)下一切正常。被调用函数不使用泛型类型和类型参数的静态上下文。但没有VS应用程序失败,没有声音。我们甚至无法识别调用堆栈附加debuger。
使用.net 4.0进行测试
问题是为什么VS捕获但运行时没有?
答案 0 :(得分:2)
嗯,是的,这表现得并不优雅。它在.NET 4.0中部分修复,CreateDelegate()方法返回null。但是,当启用JIT优化器时,它仍然没有正常运行,它假定CreateDelegate不能返回null并且不执行空检查。您将获得FatalExecutionEngineError而不是NRE,这是4.0中不再可捕获的异常
我建议您将缺陷报告给connect.microsoft.com。不太确定他们会认真对待你,当你故意绕过保障时,我不知道他们的政策是什么。很可能他们认为FEEE足够好了。解决方法很明显,只调用具体类型的方法。
答案 1 :(得分:1)
我不确定我是否完全遵循您想要做的事情,但如果您将代码放在try / catch块中,肯定会抛出异常。
答案 2 :(得分:1)
刚刚在VS 2008下测试过
VS根本没有捕获异常。
这是修改过的测试用例
static class Program
{
private delegate Foo Delegate1();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MethodInfo mi = typeof(Bar<>).GetMethod("GetClass", BindingFlags.NonPublic | BindingFlags.Static);
if (mi != null)
{
var del = (Delegate1)Delegate.CreateDelegate(typeof(Delegate1), mi);
MessageBox.Show("1");
try
{
del();
//mi.Invoke(null, BindingFlags.NonPublic | BindingFlags.Static, null, null,CultureInfo.InvariantCulture);
}
catch (Exception)
{
MessageBox.Show("No, I can`t catch it");
}
MessageBox.Show("2");
mi.Invoke(null, new object[] { });//It's Ok, we'll get exception here
MessageBox.Show("3");
}
}
class Foo
{
}
class Bar<T> : Foo
{
internal static Foo GetClass()
{
Type type = typeof(T);
MessageBox.Show("Type name " + type.FullName + " Type: " + type + " Assembly " + type.Assembly);
return new Bar<T>();
}
}
}
但是如果你评论del()并取消注释mi.Invoke()你会得到很好的例外 真。
后期绑定操作不能 对类型或方法执行 哪个ContainsGenericParameters是 真
答案 3 :(得分:1)
我不认为您发布的代码实际上是在.net框架下工作的。 2.0到4.0。静态方法只能在封闭的泛型类型上调用AFAIK,而不能在打开的泛型类型上调用。所以你必须提供一个类型参数。至于调试器,尝试在Visual Studio外部启动进程,然后附加VS-Debugger。这次你马上得到预期的例外。