Warum IEnumerable (T) implementieren, wenn ich nur EINEN GetEnumerator definieren kann?

Aktualisiere: Ich schätze alle Kommentare, die im Wesentlichen einstimmigen Widerspruch enthalten haben. Obwohl jeder Einwand berechtigt war, habe ich das Gefühl, dass der ultimative Nagel im Sarg Anis scharfsinnige Beobachtung dass letztendlich sogar dieeine miniscule Vorteil, dass diese angeblich angebotene Idee - die Eliminierung von Boilerplate-Code - durch die Tatsache negiert wurde, dass die Idee selbst ihre @ erfordern würbesitze Kesselschildcode.

So ja, halte mich für überzeugt: es wäre eine schlechte Idee.

Und um meine Würde ein wenig zu retten: Ich hätte es vielleicht aus Gründen der Argumentation durchgespielt, aber ich war anfangs nie wirklich begeistert von dieser Idee - nur gespannt, was andere dazu zu sagen hatten. Ehrlich

evor Sie diese Frage als absurd abtun, möchte ich Sie bitten, Folgendes zu beachten:

IEnumerable<T> erbt von *IEnumerable, was bedeutet, dass jeder Typ, der @ implementieIEnumerable<T> muss generell implementierenbeid IEnumerable<T>.GetEnumerator un (explizit)IEnumerable.GetEnumerator. Dies entspricht im Grunde genommen einem Kesselschildcode.Du kannstforeach über jeden Typ mit einemGetEnumerator -Methode, solange diese Methode ein Objekt eines Typs mit einem @ zurückgiMoveNext Methode und einCurrent Eigentum. Also, wenn Ihr Typ definierteine Methode mit der Signaturpublic IEnumerator<T> GetEnumerator(), es ist legal, mit @ darüber zu zählforeach. Klar, es gibt eine Menge Code, der das @ benötiIEnumerable<T> interface - zum Beispiel im Grunde alle LINQ-Erweiterungsmethoden. Zum Glück von einem Typ zu gehen, den Sie @ könnforeach weiter zu einemIEnumerable<T> ist mit der automatischen Iteratorgenerierung, die C # über das @ bereitstellt, triviyield Stichwort

So, alles in allem hatte ich diese verrückte Idee: Was ist, wenn ich nur meine eigene Schnittstelle definiere, die so aussieht:

public interface IForEachable<T>
{
    IEnumerator<T> GetEnumerator();
}

Dan Immer wenn ich einen Typ definiere, den ich aufzählen möchte, implementiere ichDie interface stattIEnumerable<T>, so dass keine zwei @ implementiert werden müssGetEnumerator Methoden (eine explizite). Beispielsweise

class NaturalNumbers : IForEachable<int>
{
   public IEnumerator<int> GetEnumerator()
   {
       int i = 1;
       while (i < int.MaxValue)
       {
           yield return (i++);
       }
   }

   // Notice how I don't have to define a method like
   // IEnumerator IEnumerable.GetEnumerator().
}

Schließlic, um diesen Typ mit Code kompatibel zu machen, der does erwarte dasIEnumerable<T> Schnittstelle kann ich nur eine Erweiterungsmethode definieren, um von jedem @ zu gehIForEachable<T> zu einemIEnumerable<T> wie so:

public static class ForEachableExtensions
{
    public static IEnumerable<T> AsEnumerable<T>(this IForEachable<T> source)
    {
        foreach (T item in source)
        {
            yield return item;
        }
    }
}

s scheint mir, dass ich auf diese Weise Typen entwerfen kann, die in jeder Hinsicht als Implementierungen von @ verwendbar sinIEnumerable<T>, aber ohne das lästige expliziteIEnumerable.GetEnumerator Implementierung in jedem.

Beispielsweise

var numbers = new NaturalNumbers();

// I can foreach myself...
foreach (int x in numbers)
{
    if (x > 100)
        break;

    if (x % 2 != 0)
        continue;

    Console.WriteLine(x);
}

// Or I can treat this object as an IEnumerable<T> implementation
// if I want to...
var evenNumbers = from x in numbers.AsEnumerable()
                  where x % 2 == 0
                  select x;

foreach (int x in evenNumbers.TakeWhile(i => i <= 100))
{
    Console.WriteLine(x);
}

Was haltet ihr von dieser Idee? Fehlt mir ein Grund, warum dies ein Fehler wäre?

Ich realisiere, dass es wahrscheinlich eine übermäßig komplexe Lösung für das ist, was anfangs nicht so wichtig ist (ich bezweifle, dass irgendjemandJa wirklic kümmert sich so sehr darum, das @ explizit definieren zu müssIEnumerable interface); Aber es ist mir einfach in den Kopf gesprungen und ich sehe keine offensichtlichen Probleme, die dieser Ansatz aufwerfen würde.

Im Allgemeinen, wenn ich eine moderate Menge an Code schreiben kannEinma um mir die Mühe zu ersparen, eine kleine Menge Code schreiben zu müssenviele Mal, für mich ist es das wert.

* Ist das die richtige Terminologie? Ich zögere immer zu sagen, dass eine Schnittstelle von einer anderen "erbt", da dies die Beziehung zwischen ihnen nicht richtig zu erfassen scheint. Aber vielleicht stimmt es ja.

Antworten auf die Frage(12)

Ihre Antwort auf die Frage