web-dev-qa-db-fra.com

Obtenir l'index actuel de la boucle foreach

Utilisation de C # et Silverlight

Comment obtenir l'index de l'élément en cours dans la liste?

Code:

IEnumerable list = DataGridDetail.ItemsSource as IEnumerable;
List<string> lstFile = new List<string>();


foreach (var row in list)
{
  bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row)).IsChecked;
  if (IsChecked)
  {

    // Here I want to get the index or current row from the list                   

  }
}

Comment y parvenir

9
Gopal
IEnumerable list = DataGridDetail.ItemsSource as IEnumerable;
List<string> lstFile = new List<string>();

int i = 0;
foreach (var row in list)
{
bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row)).IsChecked;
if (IsChecked)
{
  MessageBox.show(i);
--Here i want to get the index or current row from the list                   

}
 ++i;
}
6
tapos ghosh

Vous ne pouvez pas, car IEnumerable n'a pas d'index du tout ... si vous êtes sûr que votre énumérable a moins de int.MaxValue Éléments (ou long.MaxValue si vous utilisez un index long) , vous pouvez:

  1. N'utilisez pas foreach et utilisez une boucle for, convertissant d'abord votre IEnumerable en un énumérable générique:

    var genericList = list.Cast<object>();
    for(int i = 0; i < genericList.Count(); ++i)
    {
       var row = genericList.ElementAt(i);
       /* .... */
    }
    
  2. Avoir un index externe:

    int i = 0;
    foreach(var row in list)
    {
       /* .... */
       ++i;
    }
    
  3. Obtenez l'index via Linq:

    foreach(var rowObject in list.Cast<object>().Select((r, i) => new {Row=r, Index=i}))
    {
      var row = rowObject.Row;
      var i = rowObject.Index;
      /* .... */    
    }
    

Dans votre cas, puisque votre IEnumerable n'est pas générique, je préfère utiliser le foreach avec un index externe (deuxième méthode) ... sinon, vous voudrez peut-être faire le Cast<object> En dehors de votre boucle pour le convertir en IEnumerable<object>.

Votre type de données n'est pas clair à la question, mais je suppose que object puisqu'il s'agit d'une source d'éléments (il pourrait être DataGridRow) ... vous voudrez peut-être vérifier s'il est directement convertible en un générique IEnumerable<object> sans avoir à appeler Cast<object>(), mais je ne ferai pas de telles hypothèses.


Tout cela dit:

Le concept d'un "index" est étranger à un IEnumerable. Un IEnumerable peut être potentiellement infini. Dans votre exemple, vous utilisez le ItemsSource d'un DataGrid, donc plus probablement votre IEnumerable n'est qu'une liste d'objets (ou DataRows), avec un nombre fini (et, espérons-le, inférieur à int.MaxValue) de membres, mais IEnumerable peut représenter tout ce qui peut être énuméré (et une énumération peut potentiellement ne jamais se terminer).

Prenez cet exemple:

public static IEnumerable InfiniteEnumerable()
{
  var rnd = new Random();
  while(true)
  {
    yield return rnd.Next();
  }
}

Donc si vous le faites:

foreach(var row in InfiniteEnumerable())
{
  /* ... */
}

Votre foreach sera infini: si vous avez utilisé un index int (ou long), vous finirez par le déborder (et à moins d'utiliser un unchecked contexte, il lèvera une exception si vous continuez à y ajouter: même si vous avez utilisé unchecked, l'index serait également vide de sens ... à un moment donné -quand il débordera- l'index sera le même pour deux valeurs différentes).

Ainsi, alors que les exemples donnés fonctionnent pour une utilisation typique, je préfère ne pas utiliser du tout d'index si vous pouvez l'éviter.

20
Jcl

Utilisez Enumerable.Select <TSource, TResult>, méthode (IEnumerable <TSource>, Func <TSource, Int32, TResult>)

list = list.Cast<object>().Select( (v, i) => new {Value= v, Index = i});

foreach(var row in list)
{
    bool IsChecked = (bool)((CheckBox)DataGridDetail.Columns[0].GetCellContent(row.Value)).IsChecked;
    row.Index ...
}
1
qxg

Vous avez deux options ici, 1. Utilisez for à la place pour foreach pour l'itération. Mais dans votre cas, la collection est IEnumerable et la limite supérieure de la collection est inconnue, donc foreach sera la meilleure option . donc je préfère utiliser une autre variable entière pour tenir le nombre d'itérations: voici le code pour ça:

int i = 0; // for index
foreach (var row in list)
{
    bool IsChecked;// assign value to this variable
    if (IsChecked)
    {    
       // use i value here                
    }
    i++; // will increment i in each iteration
}
0
sujith karivelil