2008-10-21 6 views
1

J'écris une grande méthode statique qui prend un argument générique en paramètre. J'appelle cette méthode et l'infrastructure génère une exception System.InvalidProgramException. Cette exception est levée avant même que la première ligne de la méthode ne soit exécutée."CLR a détecté un programme non valide." lorsque j'appelle Generic Methods

Je peux créer une classe statique qui prend l'argument générique, puis en faire une méthode de la classe statique, et tout fonctionne bien.

Est-ce un défaut .NET, ou y a-t-il une règle générique obscure que je casse ici? Par souci d'exhaustivité, j'ai inclus la méthode qui échoue, et la méthode qui passe. Notez que cela utilise un certain nombre d'autres classes de ma propre bibliothèque (par exemple GridUtils), et ces classes ne sont pas expliquées ici. Je ne pense pas que le sens réel compte: la question est pourquoi le runtime se bloque avant même que la méthode ne commence.

(je suis la programmation avec Visual Studio 2005, alors peut-être ce qui a disparu dans Visual Studio 2008.)

Cela jette une exception avant la première ligne est invoquée:

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

Cela fonctionne très bien:

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

Est-ce pour ASP.NET, WinForms ou quoi? Qu'est-ce que l'espace de noms GridUtils? – GregUzelac

+0

L'espace de noms GridUtils fait partie de ma propre bibliothèque. Je vais préciser que c'est le message, merci. –

+0

En réponse directe à votre question, il se trouve dans WinForms. –

Répondre

0

Juste Pour votre information, pas sûr que ça va fixer quoi que ce soit, b Votre méthode Invoke peut être simplifiée. Cela supprime également la nécessité de ce délégué (qui peut conduire à une solution?):

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

Votre code fonctionne bien pour moi quand je le coller dans un formulaire (après avoir commenté votre stuff GridUtils). J'appelle même la méthode à la fois du thread gui et du thread non-gui. Je l'ai essayé en 3.5 et 2.0. Fonctionne très bien ....

Essayez ce code (!):

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

     } 

    } 
} 
0

Mise à jour en raison de me mal interpréter l'exemple de code.

Essayez d'envelopper le délégué avec un MethodInvoker:

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

+0

TGridLine n'est pas spécifié par la classe parente. En fait, il a omis la définition de la classe parente dans son premier exemple. C'est les traiter correctement. – TheSoftwareJedi

+0

Darn, il y a un cours que j'aurais aimé connaître. Mon code est jonché de délégués spécialisés dont je serai heureux de me débarrasser. –

0

Après TheSoftwareJedi's suggestion, j'ai couru quelques tests, et prouvé de façon concluante que c'est l'utilisation de la PROG_Delegate qui fait l'exception.

Si j'utilise MethodInvoker, le code s'exécute sans erreur.

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

Si je mets le PROG_Delegate en arrière et supprimer tout le reste je reçois l'exception de retour.

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

Donc, il y a une solution facile, et l'utilisation du MethodInvoker rend le code plus concis et facile à lire.Sur le plan théorique, la question se pose toujours de savoir pourquoi la fonction PROG_Delegate est légale et fonctionne pour d'autres personnes. Je pense que la meilleure réponse à laquelle nous puissions parvenir est "un bug obscur", qui restera obscur car les codeurs préfèrent utiliser Method Invoker de toute façon.

Questions connexes