2016-06-24 2 views
0

J'ai le code comme ci-dessous (je l'ai générée et réduit pour représenter juste le problème à portée de main). Le code fonctionne, c'est-à-dire qu'il prend un DataGridView.DataSource et ultimement, en utilisant EPPlus, affiche les données dans un fichier Excel. Ma question concerne la covariance et comment l'utiliser, je pense.DataGridView avec covariance?

Donc, vous voyez qu'il construit newList en fonction du type qu'il a trouvé dans le DataSource. Puis, un peu plus bas, il ajoute les données en utilisant les propriétés, someClassObject.Name, .Address and .Phone qui sont uniques à ce type.

Mon problème est qu'il y a environ 75 classes différentes qui pourraient être transmises par le paramètre DataGridView. Chaque classe a ses propres propriétés uniques (c'est-à-dire pas nécessairement le nom, l'adresse, le téléphone) bien que tous les objets donnés dans DataGridView.DataSource soient de la même classe.

Je pourrais avoir un géant commutateur d'instruction basée sur type.FullName et puis chacun aurait sa propre boucle pour assigner les valeurs de propriété à la cellule. Cela fonctionnerait mais serait incroyablement lourd. Y a-t-il une meilleure manière de faire cela?

public void openExcelReport(ref DataGridView dataGridView, bool bolSave = false, bool bolOpen = true, string pageTitle = "EXPORTED DATA") 
{ 
    // put dataGridView.DataSource into a List 
    object firstItem = null; 
    var myDataSource = dataGridView.DataSource; 
    var myList = ((System.Windows.Forms.BindingSource)dataGridView.DataSource).List; 
    firstItem = ((System.Collections.IList)myList)[0]; 
    var type = firstItem.GetType(); 

    Type PROJECT1_TYPE = typeof(Project1.SomeClass); 
    Type PROJECT2_TYPE = typeof(Project2.SomeOtherClass); // many more of these 

    dynamic newList = null; 

    if (type.FullName.Equals(PROJECT1_TYPE.FullName)) 
    { 
     newList = new List<Project1.SomeClass>(); 
     foreach (Project1.SomeClass someClassObject in myList) 
     { 
      newList.Add(someClassObject); 
     } 
    } 

    ExcelPackage package = new ExcelPackage(); 
    using ((package)) // use EPPlus 
    { 
     // Create the worksheet 
     ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1"); 

     // Load the datatable into the sheet, starting from cell A1. Print the column names on row 1 

     System.Data.DataTable dataTable = new System.Data.DataTable(); 

     dataTable.Columns.Add("Id"); 
     dataTable.Columns.Add("FirstColumn", typeof(string)); 
     dataTable.Columns.Add("SecondColumn", typeof(string)); 
     dataTable.Columns.Add("ThirdColumn", typeof(string)); 

     dataTable.Columns[0].AutoIncrement = true; 

     var column_id = 0; 
     foreach (Project1.SomeClass someClassObject in "FirstColumn") 
     { 
      DataRow dataRow = dataTable.NewRow(); 

      dataRow["FirstColumn"] = someClassObject.Name; 
      dataRow["SecondColumn"] = someClassObject.Address; 
      dataRow["ThirdColumn"] = someClassObject.Phone 

      dataTable.Rows.Add(dataRow); 

      column_id += 1; 

     } 

     // worksheet is now populated, so save Excel File  
     ... 

} 
+1

Pour les classes que vous transmettez, pourriez-vous les modifier pour implémenter une interface avec une fonction 'GetDataRow()' (ou quelque chose de similaire) afin que vous puissiez avoir ce code dans la classe elle-même, ici vous faites simplement 'dataTable.Rows.Add (someClassObject.GetDataRow())'. Et être fait avec. Cela vous éviterait d'avoir besoin d'un bloc 'switch' ou' if/else' car les informations pour générer le 'DataRow' sont directement associées à la classe contenant les colonnes potentielles en tant que propriétés. – gmiley

Répondre

2

Au lieu de faire la DataRow création au sein de cette fonction, vous pouvez le déplacer vers les implémentations de classe à l'aide d'une interface commune pour l'appliquer, par exemple:

public interface DataRowConvertable 
{ 
    DataRow GetDataRow(); 
} 

public class SomeClass : DataRowConvertable 
{ 
    public SomeClass() { } 
    public SomeClass(string name, string address, string phone) 
    { 
     Name = name; 
     Address = address; 
     Phone = phone; 
    } 

    public string Name { get; set; } 
    public string Address { get; set; } 
    public string Phone { get; set; } 

    public DataRow GetDataRow() 
    { 
     DataRow row = GetDataTable().NewRow(); 
     row["Name"] = this.Name; 
     row["Address"] = this.Address; 
     row["Phone"] = this.Phone; 
     return row; 
    } 

    public static DataTable GetDataTable() 
    { 
     DataTable table = new DataTable("SomeClassTable"); 
     table.Columns.Add("Name", typeof(string)); 
     table.Columns.Add("Address", typeof(string)); 
     table.Columns.Add("Phone", typeof(string)); 
     return table; 
    } 
} 

Vous pouvez le prendre plus, mais cela devrait vous donner une bonne alternative et un endroit pour commencer. Vous pouvez laisser la fonction GetDataTable publique, et l'utiliser aussi pour créer votre instance de table, ou la rendre privée et ne l'utiliser qu'en interne. J'opterais pour le premier et l'utiliserais dans votre fonction pour initialiser la table avant de la remplir. Vous pouvez même vous débarrasser du modificateur static et l'ajouter à votre interface, mais je préfère l'utilisation statique dans cette instance car il ne dépend pas de l'instance de la classe et des données impliquées, uniquement sur la structure.

Quoi qu'il en soit, vous pouvez alors changer le code que vous avez ci-dessus pour ressembler à ceci:

ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1"); 
System.Data.DataTable dataTable = Project1.SomeClass.GetDataTable(); 

foreach (Project1.SomeClass someClassObject in myList) 
{ 
    dataTable.Rows.Add(someClassObject.GetDataRow()); 
} 

Si vous avez besoin d'une incrémentée id colonne, vous pouvez facilement ajouter que dans les fonctions GetDataTable/GetDataRow et les mettre à jour comme vous étiez au-dessus.

Ceci est juste un exemple rapide, il pourrait très probablement être nettoyé et optimisé certains, mais il transmet toujours l'idée. J'espère que ça vous aide un peu.

+0

Merci. J'étais tellement concentré sur la "covariance" que je ne considérais rien d'autre. Je vais essayer de mettre en œuvre cela et revenir à vous. –