Question

Quelle est la meilleure façon de parcourir une liste générique fortement typée en C#.NET et VB.NET ?

Était-ce utile?

La solution

Pour C# :

foreach(ObjectType objectItem in objectTypeList)
{
    // ...do some stuff
}

Réponse pour VB.NET de Fourmi violette:

For Each objectItem as ObjectType in objectTypeList
    'Do some stuff '
Next

Autres conseils

Avec toute implémentation générique de IEnumerable, le meilleur moyen est :

//C#
foreach( var item in listVariable) {
    //do stuff
}

Il existe cependant une exception importante.IEnumerable implique une surcharge de Current() et MoveNext() dans laquelle la boucle foreach est réellement compilée.

Lorsque vous disposez d’un simple tableau de structures :

//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
     int item = valueTypeArray[i];
     //do stuff
}

C'est plus rapide.


Mise à jour

Suite à une discussion avec @Steven Sudit (voir commentaires) je pense que mon conseil initial est peut-être obsolète ou erroné, j'ai donc fait quelques tests :

// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();

// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
    int inLoop = item;
}
Console.WriteLine("list  foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theList[i];
}
Console.WriteLine("list  for    : " + sw.Elapsed.ToString());

// now run the same tests, but with an array
var theArray = theList.ToArray();

sw.Reset();
sw.Start();

foreach (var item in theArray)
{
    int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theArray[i];
}
Console.WriteLine("array for    : " + sw.Elapsed.ToString());

Console.ReadKey();

J'ai donc exécuté ceci dans la version avec toutes les optimisations :

list  foreach: 00:00:00.5137506
list  for    : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for    : 00:00:00.0954890

Et puis déboguez sans optimisations :

list  foreach: 00:00:01.1289015
list  for    : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for    : 00:00:00.4913245

Cela semble donc assez cohérent, for est plus rapide que foreach et les tableaux sont plus rapides que les listes génériques.

Cependant, cela s'étend sur 100 000 000 d'itérations et la différence est d'environ 0,4 seconde entre les méthodes les plus rapides et les plus lentes.À moins que vous n'effectuiez des boucles massives critiques en termes de performances, cela ne vaut tout simplement pas la peine de s'inquiéter.

Pour VB.NET :

For Each tmpObject as ObjectType in ObjectTypeList
    'Do some stuff '
Next

C#

myList<string>().ForEach(
    delegate(string name)
    {
        Console.WriteLine(name);
    });

Les délégués anonymes ne sont actuellement pas implémentés dans VB.Net, mais C# et VB.Net devraient être capables de faire des lambdas :

C#

myList<string>().ForEach(name => Console.WriteLine(name));

VB.Net

myList(Of String)().ForEach(Function(name) Console.WriteLine(name))

Comme Grauenwolf l'a souligné, le VB ci-dessus ne sera pas compilé puisque le lambda ne renvoie pas de valeur.Une boucle ForEach normale, comme d'autres l'ont suggéré, est probablement la plus simple pour le moment, mais comme d'habitude, il faut un bloc de code pour faire ce que C# peut faire en une seule ligne.


Voici un exemple banal de la raison pour laquelle cela pourrait être utile :cela vous donne la possibilité de transmettre la logique de boucle à partir d'une autre portée que celle où existe IEnumerable, de sorte que vous n'avez même pas besoin de l'exposer si vous ne le souhaitez pas.

Supposons que vous ayez une liste de chemins d'URL relatifs que vous souhaitez rendre absolus :

public IEnumerable<String> Paths(Func<String> formatter) {
    List<String> paths = new List<String>()
    {
        "/about", "/contact", "/services"
    };

    return paths.ForEach(formatter);
}

Vous pouvez donc appeler la fonction de cette façon :

var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);

Te donne "http://myhost.com/about", "http://myhost.com/contact" etc.Évidemment, il existe de meilleures façons d'y parvenir dans cet exemple spécifique, j'essaie simplement de démontrer le principe de base.

Sans connaître l'implémentation interne d'une liste, je pense que généralement la meilleure façon de la parcourir serait une boucle foreach.Étant donné que foreach utilise un IEnumerator pour parcourir la liste, c'est à la liste elle-même de déterminer comment passer d'un objet à l'autre.

Si l'implémentation interne était, disons, une liste chaînée, alors une simple boucle for serait un peu plus lente qu'une foreach.

Cela a-t-il du sens?

Cela dépend de votre application :

  • boucle for, si l'efficacité est une priorité
  • boucle foreach ou méthode ForEach, selon celle qui communique le plus clairement votre intention

Il me manque peut-être quelque chose, mais parcourir une liste générique devrait être assez simple si vous utilisez mes exemples ci-dessous.La classe List<> implémente les interfaces IList et IEnumerable afin que vous puissiez facilement les parcourir comme vous le souhaitez.

Le moyen le plus efficace serait d'utiliser une boucle for :

for(int i = 0; i < genericList.Count; ++i) 
{
     // Loop body
}

Vous pouvez également choisir d'utiliser une boucle foreach :

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top