我编写了一个大型静态方法,它将泛型作为参数参数。我调用此方法,框架抛出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;
}
}
答案 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,因此仍然会模糊不清。