wake-up-neo.com

IEnumerable ist leer?

Ich weiß, dass es für die meiste Zeit wahrscheinlich keine Rolle spielt/beeinflusst, aber ich hasse die Idee, ein IEnumerable zu bekommen und .Count() zu machen. Gibt es eine IsEmpty- oder NotEmpty-Funktion oder eine Funktion? (ähnlich wie stl empty ())

44
user34537

Sie wollen IEnumerable.Any () Erweiterungsmethode (.Net Framework 3.5 und höher). Es vermeidet, über die Elemente zu zählen.

74
cristobalito

wenn es nicht generisch ist als so etwas

enumeration.Cast<object>().Any();

wenn es generisch ist, verwenden Sie die Erweiterung von Enumerable wie bereits gesagt

15
Artiom

Ohne LINQ können Sie Folgendes tun:

bool IsEmpty(IEnumerable en)
{
    foreach(var c in en) { return false; }
    return true;
}
8
nothrow

Sie können Erweiterungsmethoden wie Any () oder Count () verwenden. Count () ist teurer als Any (), da es die gesamte Aufzählung ausführen muss, wie andere darauf hingewiesen haben. 

Im Falle einer langsamen Bewertung (z. B. einer Methode, die den Ertrag verwendet) kann jedoch beide kostspielig sein. Bei der folgenden IEnumerable-Implementierung entstehen beispielsweise bei jedem Aufruf von Any oder Count die Kosten für einen neuen Roundtrip zur Datenbank:

IEnumerable<MyObject> GetMyObjects(...)
{
    using(IDbConnection connection = ...)
    {
         using(IDataReader reader = ...)
         {
             while(reader.Read())
             {
                 yield return GetMyObjectFromReader(reader);
             }
         }
    }
}

Ich denke, die Moral ist:

  • Wenn Sie nur über einen IEnumerable<T> verfügen und mehr als nur eine Aufzählung durchführen möchten (z. B. Count oder Any verwenden), sollten Sie die Konvertierung zunächst in eine Liste (Erweiterungsmethode ToList) durchführen. Auf diese Weise garantieren Sie, dass Sie nur einmal aufzählen.

  • Wenn Sie eine API entwerfen, die eine Sammlung zurückgibt, sollten Sie ICollection<T> (oder sogar IList<T>) statt IEnumerable<T> zurückgeben, da viele Leute dies zu empfehlen scheinen. Auf diese Weise verstärken Sie Ihren Vertrag, um keine faulen Bewertungen (und somit keine Mehrfachbewertung) zu gewährleisten.

Bitte beachten Sie, ich sage, Sie sollten erwägen eine Sammlung zurückgeben, nicht immer eine Sammlung zurückgeben. Wie immer gibt es Kompromisse, wie aus den folgenden Kommentaren ersichtlich.

  • @KeithS meint, Sie sollten niemals mit einem DataReader nachgeben, und obwohl ich niemals nie sagen darf, würde ich sagen, dass es generell ein guter Rat ist, dass ein Data Access Layer eher einen ICollection<T> als einen faul bewerteten IEnumerable<T> zurückgibt Kommentar.

  • @Bear Monkey weist darauf hin, dass das Instanziieren einer Liste im obigen Beispiel teuer sein kann, wenn die Datenbank eine große Anzahl von Datensätzen zurückgibt. Das trifft auch zu, und in einigen (wahrscheinlich seltenen) Fällen kann es angebracht sein, den Hinweis von @ KeithS zu ignorieren und eine von Lazy ausgewertete Aufzählung zurückzugeben, vorausgesetzt, der Verbraucher unternimmt etwas, das nicht zu zeitaufwändig ist (z. B. das Generieren von Gesamtwerten).

3
Joe

Denken Sie daran, dass IEnumerable nur eine Schnittstelle ist. Die Implementierung dahinter kann von Klasse zu Klasse sehr unterschiedlich sein (siehe Joes Beispiel). Die Erweiterungsmethode IEnumerable.Any () muss ein generischer Ansatz sein und ist möglicherweise nicht das, was Sie möchten (leistungsmäßig). Yossarian schlägt ein Mittel vor, das für viele Klassen geeignet sein sollte, aber wenn die zugrunde liegende Implementierung keine Rendite verwendet, könnten Sie trotzdem einen Preis zahlen.

Wenn Sie sich an Sammlungen oder Arrays halten, die in einer IEnumerable-Schnittstelle eingeschlossen sind, haben Cristobalito und Yossarian im Allgemeinen die besten Antworten. Meine Vermutung ist die eingebaute .Any () ext-Methode, die von Yossarian empfohlen wird.

2
Les

Bei IEnumerable oder IEnumerable<T>, nein.

Aber es macht wirklich keinen Sinn. Wenn eine Auflistung leer ist und Sie versuchen, sie mithilfe von IEnumerable zu durchlaufen, gibt der Aufruf von IEnumerator.MoveNext() einfach ohne Leistungskosten false zurück.

1
Justin Niessner

Ich glaube nicht, dafür ist Count gedacht. Außerdem, was wird schneller sein:

  1. Zugriff auf eine Eigenschaft und Abrufen einer gespeicherten Integer
  2. Zugriff auf eine Eigenschaft und Abrufen einer gespeicherten Boolean
0
Bobby

Sie können auch Ihre eigenen Count-Erweiterungsmethoden-Überladungen schreiben:

    /// <summary>
    /// Count is at least the minimum specified.
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="min"></param>
    /// <returns></returns>
    public static bool Count<TSource>(this IEnumerable<TSource> source, int min)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        return source.Count(min, int.MaxValue);
    }

    /// <summary>
    /// Count is between the given min and max values
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public static bool Count<TSource>(this IEnumerable<TSource> source, int min, int max)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (min <= 0)
        {
            throw new ArgumentOutOfRangeException("min", "min must be a non-zero positive number");
        }
        if (max <= 0)
        {
            throw new ArgumentOutOfRangeException("max", "max must be a non-zero positive number");
        }
        if (min >= max)
            throw new ArgumentOutOfRangeException("min and max", "min must be lest than max");

        var isCollection = source as ICollection<TSource>;

        if (isCollection != null)
            return isCollection.Count >= min && isCollection.Count <= max;

        var count = 0;
        using (var enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                count++;
                if (count >= min && count <= max)
                    return true;
            }
        }
        return false;
    }
0
Jonathan Parker