J'essaye de parcourir un datatable et d'imprimer les valeurs

  • 0,
  • 1 et
  • 4ème cellule de chaque ligne,

Et j'ai l'impression que cela devrait fonctionner, mais je suis probablement en train de gâcher la boucle.

 foreach (DataRow dr in dt.Rows)
 {
      for (int x = 0; x < dt.Rows.Count; x++)
      {
          Console.WriteLine(dt.Columns[0].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
          Console.WriteLine(dt.Columns[1].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
          Console.WriteLine(dt.Columns[4].ColumnName + " ");
          Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
       }
 }

Le code ci-dessus me donne cette erreur:

Le système ne peut pas exécuter le programme spécifié.

0
chessmt 28 août 2020 à 08:12

3 réponses

Meilleure réponse

Vous n'avez pas besoin d'entourer votre boucle for d'une boucle foreach sur les lignes. (Vous n'utilisez pas du tout le dr)

for (int idx = 0; idx < dt.Rows.Count; idx++)
{
    Console.WriteLine(dt.Columns[0].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[0] + " ");
    Console.WriteLine(dt.Columns[1].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[1] + " ");
    Console.WriteLine(dt.Columns[4].ColumnName + " ");
    Console.WriteLine(dt.Rows[idx].ItemArray[4] + " ");
}

Une version un peu plus générique:

int[] columnIndexes = new[] { 0, 1, 4 };
for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
    {
        Console.WriteLine(dt.Columns[columnIndex].ColumnName + " ");
        Console.WriteLine(dt.Rows[rowIndex].ItemArray[columnIndex] + " ");
    }
}

Si vous souhaitez parcourir la collection Rows avec foreach, vous pouvez le faire, mais c'est un peu plus délicat.

La propriété Rows de DataTable est un DataRowCollection . Il expose une méthode GetEnumerator, qui est essentielle pour la boucle foreach.

foreach (DataRow dr in dt.Rows)
{
    //dr does not provide you direct access to the ColumnName
}

Vous ne pouvez pas accéder directement au ColumnName à partir du DataRow. Il suffit de créer une "table de recherche" pour les noms de colonnes où la clé est l'index et la valeur est le nom de la colonne.

int colIdx = 0;
var columnNames = dt.Columns
    .Cast<DataColumn>()
    .ToDictionary(_ => colIdx++, column => column.ColumnName);

Après cela, votre boucle foreach ressemblerait à ceci:

int[] columnIndexes = new[] {0, 1, 4};
foreach (DataRow row in dt.Rows)
{
    for (int columnIndex = 0; columnIndex < columnIndexes.Length; columnIndex++)
    {
        Console.WriteLine(columnNames[columnIndex] + " ");
        Console.WriteLine(row.ItemArray[columnIndex] + " ");
    }
}
1
Peter Csala 29 août 2020 à 09:18

Je voulais juste souligner que vous pouvez en effet accéder aux valeurs dans un DataRow par nom de la colonne. Cette fonctionnalité est disponible dans le cadre complet .net ainsi que dans le noyau .net (vous êtes donc couvert quel que soit celui que vous utilisez). Ceci a bien sûr un léger impact sur les performances car il semble finir par faire une recherche Dictionary.

Un avantage que vous obtenez en empruntant cette voie est que vous serez moins dépendant des changements de structure de table à l'avenir - ce qui pourrait être un compromis à considérer.

Alors votre intention pourrait être exprimée comme ceci:

foreach (DataRow row in dt.Rows)
    Console.WriteLine($"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}");

Maintenant, supposons que vous vouliez abandonner foreach et continuer LINQ:

void Main()
{
    var dt = new DataTable();
    dt.Columns.Add("Col0", typeof(string));
    dt.Columns.Add("Col1", typeof(string));
    dt.Columns.Add("Col2", typeof(string));
    dt.Columns.Add("Col3", typeof(string));
    dt.Columns.Add("Col4", typeof(string));
    
    dt.Rows.Add("one","two","three","four","five");
    dt.Rows.Add("ten","eleven","twelve","thirteen","fourteen");

    var formattedItems = dt.Rows // declaring a lise you'd open yourself up to further processing the results rather than just pringint them
                            .Cast<DataRow>() // DataRow collection does implement IEnumerable through its base InternalDataCollectionBase class but we seem to need this cast in order to properly expose it
                            .Select(row => $"{row["Col0"]} - {row["Col1"]} - {row["Col4"]}") // and now we can unleash the LINQ
                            .ToList(); // depending on your further processing code you can either enumerate it now or have it sitting around until you actually need to loop through it
    
    Console.WriteLine(formattedItems.Aggregate(new StringBuilder(), (sb, s) => sb.AppendLine(s)).ToString()); // just slapping list items together in a string to print out for your convenience
}
0
timur 29 août 2020 à 23:19

Supprimez l'une des boucles:

                for (int x = 0; x < dt.Rows.Count; x++)
                {
                    Console.WriteLine(dt.Columns[0].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[0].ToString() + " ");
                    Console.WriteLine(dt.Columns[1].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[1].ToString() + " ");
                    Console.WriteLine(dt.Columns[4].ColumnName + " ");
                    Console.WriteLine(dt.Rows[x].ItemArray[4].ToString() + " ");
                }

Ou

                foreach (DataRow dr in dt.Rows){
                    Console.WriteLine($"{dr[0]} - {dr[1]} - {dr[4]}");
                }
2
t00n 28 août 2020 à 06:57