“CLR检测到无效程序。”调用通用方法时

时间:2008-10-21 01:34:47

标签: c# generics .net-2.0

我编写了一个大型静态方法,它将泛型作为参数参数。我调用此方法,框架抛出System.InvalidProgramException。甚至在执行方法的第一行之前就抛出此异常。

我可以创建一个静态类,它接受泛型参数,然后使它成为静态类的方法,一切正常。

这是一个.NET缺陷,还是有一些模糊的通用规则我在这里打破?

为了完整起见,我已经包括失败的方法和通过的方法。请注意,这使用了我自己的库中的许多其他类(例如GridUtils),这里没有解释这些类。我认为实际意义并不重要:问题是为什么在方法开始之前运行时崩溃。

(我正在使用Visual Studio 2005进行编程,所以可能在Visual Studio 2008中已经消失了。)

这会在调用第一行之前抛出异常:

    private delegate void PROG_Delegate<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns);

    public static void PopulateReadOnlyGrid<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns)
    {
        if (dgv.InvokeRequired)
        {
            dgv.BeginInvoke
                        (
                            new PROG_Delegate<TGridLine>(PopulateReadOnlyGrid<TGridLine>),
                            new object[] { dgv, gridLines, columns }
                        );
            return;
        }
        GridUtils.StatePreserver statePreserver = new GridUtils.StatePreserver(dgv);
        System.Data.DataTable dt = CollectionHelper.ConvertToDataTable<TGridLine>((gridLines));
        dgv.DataSource = dt;
        dgv.DataMember = "";
        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
        GridUtils.OrderColumns<TGridLine>(dgv, columns);
        statePreserver.RestoreState();
        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    }

这很好用:

    public static class Populator<TGridLine>
    {
        private delegate void PROG_Delegate(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns);

        public static void PopulateReadOnlyGrid(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns)
        {
            if (dgv.InvokeRequired)
            {
                dgv.BeginInvoke
                            (
                                new PROG_Delegate(PopulateReadOnlyGrid),
                                new object[] { dgv, gridLines, columns }
                            );
                return;
            }
            GridUtils.StatePreserver statePreserver = new GridUtils.StatePreserver(dgv);
            System.Data.DataTable dt = CollectionHelper.ConvertToDataTable<TGridLine>((gridLines));
            dgv.DataSource = dt;
            dgv.DataMember = "";
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            GridUtils.OrderColumns<TGridLine>(dgv, columns);
            statePreserver.RestoreState();
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;

        }
    }        

3 个答案:

答案 0 :(得分:0)

仅供参考,不确定它是否能解决任何问题,但您的Invoke方法可以简化。这也消除了对该委托的需要(可能导致修复?):

dgv.BeginInvoke(new MethodInvoker(delegate()
{
    PopulateReadOnlyGrid(dgv, gridLines, columns);
}));

当我将代码粘贴到表单中时(在注释掉GridUtils之后),我的代码运行正常。我甚至从gui线程和非gui线程调用该方法。我在3.5和2.0中尝试过它。工作正常....(!?)

试试这段代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private delegate void PROG_Delegate<TGridLine>(Control dgv, IEnumerable<TGridLine> gridLines, string[] columns);

        public static void PopulateReadOnlyGrid<TGridLine>(Control dgv, IEnumerable<TGridLine> gridLines, string[] columns)
        {
            if (dgv.InvokeRequired)
            {
                dgv.BeginInvoke
                            (
                                new PROG_Delegate<TGridLine>(PopulateReadOnlyGrid<TGridLine>),
                                new object[] { dgv, gridLines, columns }
                            );
                return;
            }
            MessageBox.Show("hi");
            //GridUtils.StatePreserver statePreserver = new GridUtils.StatePreserver(dgv);
            //System.Data.DataTable dt = CollectionHelper.ConvertToDataTable<TGridLine>((gridLines));
            //dgv.DataSource = dt;
            //dgv.DataMember = "";
            //dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            //GridUtils.OrderColumns<TGridLine>(dgv, columns);
            //statePreserver.RestoreState();
            //dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            PopulateReadOnlyGrid(this, new int[] { 1, 2, 3 }, new string[] { "a" });

            ThreadPool.QueueUserWorkItem(new WaitCallback((a) =>
            {
                PopulateReadOnlyGrid(this, new int[] { 1, 2, 3 }, new string[] { "a" });
            }));

        }

    }
}

答案 1 :(得分:0)

因我错误解释代码示例而更新。

尝试使用MethodInvoker包装委托:

http://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker.aspx

答案 2 :(得分:0)

根据TheSoftwareJedi's建议,我进行了一些测试,并最终证明使用导致异常的PROG_Delegate。

如果我使用MethodInvoker,代码运行时没有错误。

    private delegate void PROG_Delegate<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns);

    public static void PopulateReadOnlyGrid<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns)
    {
        if (dgv.InvokeRequired)
        {
            dgv.BeginInvoke(new MethodInvoker(delegate()
            {
                PopulateReadOnlyGrid(dgv, gridLines, columns);
            }));
            return;
        }
        GridUtils.StatePreserver statePreserver = new GridUtils.StatePreserver(dgv);
        System.Data.DataTable dt = CollectionHelper.ConvertToDataTable<TGridLine>((gridLines));
        dgv.DataSource = dt;
        dgv.DataMember = "";
        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
        GridUtils.OrderColumns<TGridLine>(dgv, columns);
        statePreserver.RestoreState();
        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    }

如果我重新插入PROG_Delegate并删除其他所有内容,我会收到异常。

    private delegate void PROG_Delegate<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns);

    public static void PopulateReadOnlyGrid<TGridLine>(DataGridView dgv, IEnumerable<TGridLine> gridLines, string[] columns)
    {
        if (dgv.InvokeRequired)
        {
            dgv.BeginInvoke
                        (
                            new PROG_Delegate<TGridLine>(PopulateReadOnlyGrid<TGridLine>),
                            new object[] { dgv, gridLines, columns }
                        );
        }
        //GridUtils.StatePreserver statePreserver = new GridUtils.StatePreserver(dgv);
        //System.Data.DataTable dt = CollectionHelper.ConvertToDataTable<TGridLine>((gridLines));
        //dgv.DataSource = dt;
        //dgv.DataMember = "";
        //dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
        //GridUtils.OrderColumns<TGridLine>(dgv, columns);
        //statePreserver.RestoreState();
        //dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    }

因此,有一个简单的解决方法,使用MethodInvoker可以使代码更简洁,更易读。

在理论层面上,由于PROG_Delegate是合法的并且正在为其他人工作,因此仍然存在一个问题,即它为什么会崩溃。我怀疑我们可以得到的最佳答案是“一些模糊不清的错误”,由于程序员更喜欢使用Method Invoker,因此仍然会模糊不清。