Wenn es ein Stück Code gibt, den Sie die ganze Zeit wiederholen, wiederholen Sie es in Ihrer eigenen Bibliothek und rufen Sie das an. In diesem Sinne gibt es zwei Aspekte, um hier die richtige Antwort zu finden. Die erste ist Klarheit und Kürze im Code, der die Bibliotheksfunktion aufruft. Die zweite ist die Auswirkungen auf die Leistung von foreach.
Zuerst lassen Sie uns über die Klarheit und Kürze im aufrufenden Code nachdenken.
Sie können in einer Reihe von Möglichkeiten foreach tun:
- for-Schleife
- foreach Schleife
- Collection.ForEach
Aus all den Möglichkeiten, eine foreach Liste zu tun. ForEach mit einer Lamba ist die klarste und kurzeste.
list.ForEach(i => Console.Write("{0}\t", i));
Also in diesem Stadium kann es wie die Liste aussehen. Für jeden ist der Weg zu gehen. Wie ist die Leistung davon? Es stimmt, dass in diesem Fall die Zeit für das Schreiben in die Konsole die Leistung des Codes bestimmt. Wenn wir etwas über die Leistung eines bestimmten Sprachmerkmals wissen, sollten wir es zumindest berücksichtigen.
Laut Duston Campbell's performance measurements of foreach ist der schnellste Weg zur Iteration der Liste unter optimiertem Code die Verwendung einer for-Schleife ohne Aufruf von List.Count.
Die for-Schleife ist jedoch ein ausführliches Konstrukt. Es wird auch als ein sehr iterativer Weg gesehen, Dinge zu tun, die nicht mit dem gegenwärtigen Trend zu funktionalen Idiomen übereinstimmen.
Also können wir Kürze, Klarheit und Leistung bekommen? Wir können mit einer Erweiterungsmethode arbeiten. In einer idealen Welt würden wir eine Erweiterungsmethode für Console erstellen, die eine Liste annimmt und sie mit einem Begrenzer schreibt. Dies ist nicht möglich, weil Console eine statische Klasse ist und Erweiterungsmethoden nur für Instanzen von Klassen funktionieren. Stattdessen müssen wir die Erweiterungsmethode auf die Liste setzen sich (laut David B Vorschlag):
public static void WriteLine(this List<int> theList)
{
foreach (int i in list)
{
Console.Write("{0}\t", t.ToString());
}
Console.WriteLine();
}
Dieser Code an vielen Orten verwendet wird, so sollten wir folgende Verbesserungen durchführen:
- Anstatt foreach zu verwenden, sollten wir den schnellsten Weg der Iteration der Sammlung verwenden, die eine for-Schleife mit einer zwischengespeicherten Zählung ist.
- Derzeit kann nur List als Argument übergeben werden. Als Bibliotheksfunktion können wir sie mit geringem Aufwand verallgemeinern.
- Verwenden von List beschränkt uns nur auf Listen, die Verwendung von IList ermöglicht diesen Code auch mit Arrays zu arbeiten.
- Da die Extension-Methode auf eine IList wir müssen sein wird, den Namen ändern, um zu verdeutlichen, was wir schreiben an:
Hier ist, wie der Code für die Funktion aussehen würde:
public static void WriteToConsole<T>(this IList<T> collection)
{
int count = collection.Count();
for(int i = 0; i < count; ++i)
{
Console.Write("{0}\t", collection[i].ToString(), delimiter);
}
Console.WriteLine();
}
Wir können dies noch weiter verbessern, indem wir dem Client erlauben, das Trennzeichen zu übergeben. Wir könnten dann eine zweite Funktion zur Verfügung stellen, die mit dem Standard-Trennzeichen wie diese zu trösten schreibt:
public static void WriteToConsole<T>(this IList<T> collection)
{
WriteToConsole<T>(collection, "\t");
}
public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
int count = collection.Count();
for(int i = 0; i < count; ++i)
{
Console.Write("{0}{1}", collection[i].ToString(), delimiter);
}
Console.WriteLine();
}
So, jetzt, da wir einen kurzen wollen, klare performante Art und Weise des Schreibens Listen an die Konsole wir eine haben. Hier gesamte Quellcode einschließlich einer Demonstration der Verwendung der die Bibliotheksfunktion:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleWritelineTest
{
public static class Extensions
{
public static void WriteToConsole<T>(this IList<T> collection)
{
WriteToConsole<T>(collection, "\t");
}
public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
int count = collection.Count();
for(int i = 0; i < count; ++i)
{
Console.Write("{0}{1}", collection[i].ToString(), delimiter);
}
Console.WriteLine();
}
}
internal class Foo
{
override public string ToString()
{
return "FooClass";
}
}
internal class Program
{
static void Main(string[] args)
{
var myIntList = new List<int> {1, 2, 3, 4, 5};
var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};
// Using the standard delimiter /t
myIntList.WriteToConsole();
myDoubleList.WriteToConsole();
myDoubleArray.WriteToConsole();
myFooList.WriteToConsole();
// Using our own delimiter ~
myIntList.WriteToConsole("~");
Console.Read();
}
}
}
============================ ========================
Sie könnten denken, dass dies das Ende der Antwort sein sollte. Es gibt jedoch noch eine weitere Verallgemeinerung, die getan werden kann. Aus Fatcat's Frage geht nicht hervor, ob er immer an die Konsole schreibt. Vielleicht ist etwas anderes in der Zukunft zu tun. In diesem Fall wird die Antwort von Jason Bunting diese Allgemeinheit geben. Hier ist seine Antwort wieder:
list.ForEach(i => Console.Write("{0}\t", i));
Das heißt, wenn wir eine weitere Verfeinerung unserer Erweiterungsmethoden machen, und fügen Sie FastForEach wie folgt:
public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
{
int count = collection.Count();
for (int i = 0; i < count; ++i)
{
actionToPerform(collection[i]);
}
Console.WriteLine();
}
Dies ermöglicht es uns, einen beliebigen Code gegen jedes Element auszuführen in der Sammlung mit der schnellstmöglichen Iterationsmethode.
Wir können sogar die WriteToConsole Funktion ändern FastForEach
public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
}
So, jetzt den gesamten Quellcode, darunter ein Beispiel für die Verwendung von FastForEach zu verwenden ist:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleWritelineTest
{
public static class Extensions
{
public static void WriteToConsole<T>(this IList<T> collection)
{
WriteToConsole<T>(collection, "\t");
}
public static void WriteToConsole<T>(this IList<T> collection, string delimiter)
{
collection.FastForEach(item => Console.Write("{0}{1}", item.ToString(), delimiter));
}
public static void FastForEach<T>(this IList<T> collection, Action<T> actionToPerform)
{
int count = collection.Count();
for (int i = 0; i < count; ++i)
{
actionToPerform(collection[i]);
}
Console.WriteLine();
}
}
internal class Foo
{
override public string ToString()
{
return "FooClass";
}
}
internal class Program
{
static void Main(string[] args)
{
var myIntList = new List<int> {1, 2, 3, 4, 5};
var myDoubleList = new List<double> {1.1, 2.2, 3.3, 4.4};
var myDoubleArray = new Double[] {12.3, 12.4, 12.5, 12.6};
var myFooList = new List<Foo> {new Foo(), new Foo(), new Foo()};
// Using the standard delimiter /t
myIntList.WriteToConsole();
myDoubleList.WriteToConsole();
myDoubleArray.WriteToConsole();
myFooList.WriteToConsole();
// Using our own delimiter ~
myIntList.WriteToConsole("~");
// What if we want to write them to separate lines?
myIntList.FastForEach(item => Console.WriteLine(item.ToString()));
Console.Read();
}
}
}
Beat Sie um etwa 30 Sekunden. :) –