Frage

Aktualisieren : Ich alle Kommentare zu schätzen wissen, die im Wesentlichen einig Opposition bestehen haben. Während jede Einwand gültig war, glaube ich, dass der ultimative Nagel im Sarg war Ani kluge Beobachtung , dass letztendlich auch der ein miniscule Vorteil, dass diese Idee angeblich angeboten - die Beseitigung von vorformulierten Code -. wurde durch die Tatsache negiert, dass die Idee selbst würde seinen eigenen Standardcode erfordert

Also ja, sollten Sie mich überzeugt. Es wäre eine schlechte Idee sein

Und nur um eine Art Bergungs meine Würde etwas: Ich habe es vielleicht gespielt Argument willen, aber ich war nie wirklich auf dieser Idee verkauft zu beginnen - nur neugierig zu hören, was andere hatten darüber zu sagen. Ehrlich.


Bevor Sie diese Frage als absurd abtun, frage ich Sie, folgendes zu beachten:

  1. IEnumerable<T> erbt von * IEnumerable, was bedeutet, dass jede Art der Geräte IEnumerable<T> allgemein implementieren müssen beide IEnumerable<T>.GetEnumerator und (explizit) IEnumerable.GetEnumerator. Dies entspricht im Wesentlichen auf Standardcode.
  2. Sie können jede Art foreach über die eine GetEnumerator Methode hat, solange diese Methode gibt ein Objekt eines Typs mit einem MoveNext Verfahren und eine Current Eigenschaft. Also, wenn Ihr Typ definiert ein Methode mit der Signatur public IEnumerator<T> GetEnumerator(), ist es legal, sie aufzuzählen über foreach verwenden.
  3. Offensichtlich gibt es eine Menge Code gibt, die die IEnumerable<T> Schnittstelle benötigt - zum Beispiel, im Grunde alle die LINQ-Erweiterungsmethoden. Zum Glück, zu einer Art zu gehen, dass Sie auf einen foreach IEnumerable<T> auf können trivial ist die automatische Iterator Generation mit, dass C # liefert über das yield Stichwort.

Also, das alles zusammen setzen, ich hatte diese verrückte Idee: Was, wenn ich nur meine eigene Schnittstelle definieren, dass sieht wie folgt aus:

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

Dann , wenn ich eine Art definieren, dass ich will enumerable sein, ich implementieren diese Schnittstelle statt IEnumerable<T>, entfällt die Notwendigkeit, zwei GetEnumerator Methoden zu implementieren (eine ausdrückliche) . Zum Beispiel:

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ßlich , um diese Art mit Code kompatibel zu machen, dass hat die IEnumerable<T> Schnittstelle erwartet, kann ich nur eine Erweiterungsmethode definiere von jedem IForEachable<T> zu einem IEnumerable<T> gehen etwa so:

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

Es scheint mir, dass dies zu tun ermöglicht es mir, Arten zu entwerfen, die in jeder Hinsicht als Implementierungen von IEnumerable<T> verwendbar sind, aber ohne diese lästigen explizite IEnumerable.GetEnumerator Implementierung in jedem.

Zum Beispiel:

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 denkt ihr von dieser Idee? Bin ich aus irgendeinem Grund fehlt, warum dies ein Fehler sein würde?

Ich weiß, es scheint wahrscheinlich wie eine zu komplexer Lösung zu dem, was ist nicht so große Sache, mit zu beginnen (ich bezweifle, jemand wirklich Sorgen, dass viel darüber, dass explizit die IEnumerable Schnittstelle definieren) ; aber es nur tauchte in meinem Kopf und ich bin keine offensichtlichen Probleme zu sehen, dass dieser Ansatz darstellen würde.

In der Regel, wenn ich eine moderate Menge an Code schreiben kann einmal mir die Mühe, sparen eine kleine Menge Code viele Male schreiben , mir , es lohnt sich.

* Ist das die richtige Terminologie zu bedienen? Ich bin immer zögerlich eine Schnittstelle „erbt von“ zu sagen, einem anderen, als dass nicht richtig scheinen, um die Beziehung zwischen ihnen zu erfassen. Aber vielleicht ist es richtig auf.

War es hilfreich?

Lösung

Sind nicht nur Sie die vorformulierten bewegen woanders - von der IEnumerable.GetEnumeratormethod Schreiben auf jede Klasse Ihre AsEnumerable Erweiterung ein IEnumerable<T> jedes Mal Aufruf erwartet? Normalerweise würde ich eine zählbare Art zur Abfrage weit mehr Zeit verwendet werden erwarten, als es geschrieben ist (was genau einmal ist). Dies würde bedeuten, dass dieses Muster führen mehr vorformulierten, im Durchschnitt.

Andere Tipps

Sie sind eine große Sache fehlt -

Wenn Sie eine eigene Schnittstelle statt IEnumerable<T> implementieren, Ihre Klasse wird nicht die Arbeit mit den Rahmen Methoden IEnumerable<T> erwarten - vor allem, werden Sie völlig unfähig sein LINQ zu verwenden, oder verwenden Sie Ihre Klasse eine List<T>, oder viele andere nützliche Abstraktionen zu konstruieren .

Sie können dies erreichen, wie Sie über eine separate Erweiterungsmethode erwähnen, - aber dies ist mit Kosten verbunden. Durch die Verwendung eines Verlängerungsverfahren zu konvertieren zu einem IEnumerable<T>, du bist das Hinzufügen eines weiteren Abstraktionsebene erforderlich, um die Klasse zu verwenden (die Sie FAR oft mehr tun, als die Klasse Authoring) und Sie verringern die Leistung (Ihre Erweiterungsmethode wird in der Tat, erzeugt intern eine neue Klasse Implementierung, die wirklich nicht notwendig ist). Am wichtigsten ist, jeder andere Benutzer Ihrer Klasse (oder später) muss eine neue API lernen, die nichts erreicht - Sie Ihre Klasse erschwert durch nicht unter Verwendung von Standard-Schnittstellen zu verwenden, da es die Benutzer-Erwartungen verletzt.

Du hast Recht. Es hat scheint eine zu komplexe Lösung für ein ziemlich einfaches Problem

Es führt auch eine zusätzliche Dereferenzierungsebene für jeden Schritt der Iteration. Wahrscheinlich kein Leistungsproblem, aber immer noch etwas unnötig, wenn ich glaube nicht, dass du wirklich etwas von großer Bedeutung gewinnt.

Auch, obwohl Ihre Erweiterung Methode können Sie jede IForEachable<T> in eine IEnumerable<T> konvertieren, es bedeutet, dass Ihre Art sich nicht eine generische Einschränkung wie folgt erfüllen:

public void Foo<T>(T collection) where T : IEnumerable

oder dergleichen. Im Grunde genommen, indem Sie Ihre Konvertierung, Sie verlieren die Fähigkeit, ein einzelnes Objekt als beide eine Implementierung von IEnumerable<T> und die wirklichen konkreten Art zu behandeln.

Auch durch nicht IEnumerable Implementierung, bist du selbst aus der Sammlung Initialisierungen zu zählen. (Ich manchmal implementieren IEnumerable explizit nur zu opt in der Sammel Initialisierung, eine Ausnahme von GetEnumerator() zu werfen.)

Oh, und Sie haben auch ein zusätzliches Bit der Infrastruktur eingeführt, die für alle anderen in der Welt nicht vertraut ist, verglichen mit den riesigen Horden von C # Entwickler, die bereits über IEnumerable<T> kennen.

In unserer Code-Basis gibt es wahrscheinlich mehr als 100 Fälle dieser genauen Snippet:

IEnumerator IEnumerable.GetEnumerator()
{
    return this.GetEnumerator();
}

Und ich bin wirklich mit dem OKAY. Es ist ein kleiner Preis zu zahlen für die volle Kompatibilität mit jedem anderen Stück .NET-Code jemals geschrieben;)

Ihre vorgeschlagene Lösung erfordert im Wesentlichen jeden Verbraucher / Anrufer Ihrer neuen Schnittstelle auch eine spezielle Erweiterung Methode zu nennen zu erinnern, bevor es ist nützlich .

Es ist so viel einfacher IEnumerable für Reflexion zu verwenden. Der Versuch, generische Schnittstellen über Reflexion aufzurufen ist so ein Schmerz. Die Strafe des Boxens über IEnumerable wird durch den Overhead der Reflexion verloren sich, warum so stört eine generische Schnittstelle? Als ein Beispiel, kommt Serialisierung in dem Sinne.

Ich denke, jeder hat bereits die technischen Gründen erwähnt, dies nicht zu tun, so dass ich dies in den Mix werden: benötigen Sie Ihren Benutzer AsEnumerable () auf Ihrer Sammlung aufrufen zu können, zählbare Erweiterungen verwenden würde verletzen das Prinzip der dest Überraschung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top