使用和不使用调试器的反射通用委托的不同行为

时间:2010-05-17 09:28:52

标签: c# .net reflection delegates generics

我们在调用反映的通用委托时遇到了一些奇怪的事情。在某些情况下,使用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>();
            }
        }
    }
}

有两个问题:

  1. 行为与调试器不同,没有
  2. 如果没有调试器,clr技巧就无法捕获此错误。这不是clr例外。有内存访问通道,读取内部代码内的零指针。
  3. 用例: 您为应用程序开发了类似插件系统的东西。您阅读外部程序集,找到某种类型的合适方法,然后执行它。我们忘记了我们需要检查的类型是否通用。在VS(和.net从2.0到4.0)下一切正常。被调用函数不使用泛型类型和类型参数的静态上下文。但没有VS应用程序失败,没有声音。我们甚至无法识别调用堆栈附加debuger。

    使用.net 4.0进行测试

    问题是为什么VS捕获但运行时没有?

4 个答案:

答案 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。这次你马上得到预期的例外。