Frage

Was ist der beste Weg, eine stark typisierte generische Liste in C#.NET und VB.NET zu durchlaufen?

War es hilfreich?

Lösung

Für C#:

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

Antwort für VB.NET von Lila Ameise:

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

Andere Tipps

Bei jeder generischen Implementierung von IEnumerable ist der beste Weg:

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

Es gibt jedoch eine wichtige Ausnahme.IEnumerable beinhaltet einen Overhead von Current() und MoveNext(), in den die foreach-Schleife tatsächlich kompiliert wird.

Wenn Sie ein einfaches Array von Strukturen haben:

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

Geht schneller.


Aktualisieren

Nach einer Diskussion mit @Steven Sudit (siehe Kommentare) denke ich, dass mein ursprünglicher Rat möglicherweise veraltet oder falsch ist, also habe ich einige Tests durchgeführt:

// 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();

Also habe ich dies in der Version mit allen Optimierungen ausgeführt:

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

Und dann ohne Optimierungen debuggen:

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

Es scheint also ziemlich konsistent zu sein, for ist schneller als foreach und Arrays sind schneller als generische Listen.

Dies gilt jedoch für 100.000.000 Iterationen und der Unterschied zwischen der schnellsten und der langsamsten Methode beträgt etwa 0,4 Sekunden.Es lohnt sich einfach nicht, sich darüber Gedanken zu machen, es sei denn, Sie führen massive leistungskritische Schleifen durch.

Für VB.NET:

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

C#

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

Anonyme Delegaten sind derzeit nicht in VB.Net implementiert, aber sowohl C# als auch VB.Net sollten in der Lage sein, Lambdas auszuführen:

C#

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

VB.Net

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

Wie Grauenwolf betonte, lässt sich das obige VB nicht kompilieren, da das Lambda keinen Wert zurückgibt.Eine normale ForEach-Schleife, wie andere vorgeschlagen haben, ist derzeit wahrscheinlich die einfachste, aber wie üblich ist ein Codeblock erforderlich, um das zu tun, was C# in einer Zeile tun kann.


Hier ist ein banales Beispiel dafür, warum dies nützlich sein könnte:Dies gibt Ihnen die Möglichkeit, die Schleifenlogik von einem anderen Bereich als dem, in dem IEnumerable vorhanden ist, zu übergeben, sodass Sie sie nicht einmal verfügbar machen müssen, wenn Sie dies nicht möchten.

Angenommen, Sie haben eine Liste relativer URL-Pfade, die Sie absolut machen möchten:

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

    return paths.ForEach(formatter);
}

Dann könnten Sie die Funktion also folgendermaßen aufrufen:

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

Dir geben "http://myhost.com/about", "http://myhost.com/contact" usw.Offensichtlich gibt es in diesem speziellen Beispiel bessere Möglichkeiten, dies zu erreichen. Ich versuche nur, das Grundprinzip zu demonstrieren.

Ohne die interne Implementierung einer Liste zu kennen, denke ich, dass der beste Weg, darüber zu iterieren, im Allgemeinen eine foreach-Schleife wäre.Da foreach zum Durchlaufen der Liste einen IEnumerator verwendet, liegt es an der Liste selbst, zu bestimmen, wie von Objekt zu Objekt verschoben wird.

Wenn die interne Implementierung beispielsweise eine verknüpfte Liste wäre, wäre eine einfache for-Schleife um einiges langsamer als eine foreach.

Ist das sinnvoll?

Es hängt von Ihrer Anwendung ab:

  • for-Schleife, wenn Effizienz Priorität hat
  • foreach-Schleife oder ForEach-Methode, je nachdem, was Ihre Absicht klarer kommuniziert

Möglicherweise übersehe ich etwas, aber das Durchlaufen einer generischen Liste sollte ziemlich einfach sein, wenn Sie meine Beispiele unten verwenden.Die List<>-Klasse implementiert die Schnittstellen IList und IEnumerable, sodass Sie sie problemlos und grundsätzlich nach Ihren Wünschen durchlaufen können.

Der effizienteste Weg wäre die Verwendung einer for-Schleife:

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

Sie können sich auch für die Verwendung einer foreach-Schleife entscheiden:

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top