AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Custom Enumerator

Custom Enumerator

Ein Thema von Stevie · begonnen am 21. Sep 2010
Antwort Antwort
Benutzerbild von Stevie
Stevie
Registriert seit: 12. Aug 2003
Dass man seit einigen Delphi Versionen mit der for-in-Schleife elegant über Listen, Enums und Arrays rutschen kann, wissen ja inzwischen viele.

Wahrscheinlich wissen auch einige, was man selber implementieren muss, um ein eigenes Objekt enumerable zu machen.

Aber habt ihr euch schonmal gewünscht ein Enumerable zur Laufzeit selber zu erstellen, ohne es erst in einen enumerable Container (z.B. Array oder Liste) zu werfen?

Angenommen, ich möchte die Fibonacci Zahlen ermitteln und ausgeben.
Zugegeben, das Beispiel ist eventuell ein bisschen simpel, aber ich finde, man kann damit gut das Prinzip darstellen.

Ich benutz mal die iterative Lösung (jaja, da kann man bestimmt noch was optimieren, ich weiß):
Delphi-Quellcode:
procedure FibonacciNumbers;
var
  a, b, c: UInt64;
begin
  a := 0;
  b := 1;
  Writeln(a);
  Writeln(b);
  repeat
    c := a + b;
    a := b;
    b := c;
    Writeln(c);
  until c > (High(UInt64) div 2);
end;
Ok, fein, das gibt mir also alle Fibonacci Zahlen aus, die mit UInt64 möglich sind.

Was ist, wenn ich die Zahlen nun in ne Liste packen will? Ich schreib statt Writeln dort nen list.Add rein. Was wäre, wenn ich folgendes machen könnte:

Delphi-Quellcode:
var
  i: Uint64;
begin
  for i in FibonacciNumbers() do
    Writeln(i); // oder list.Add(i);
end;
Ich kann auch die Anzahl der ermittelten Zahlen bekommen: FibonacciNumbers().Count();
Oder ich will aus irgendeinem Grund die ersten 20 überspringen und dann nur die nächsten 50 sehen: for i in FibonacciNumbers().Skip(20).Take(50) do
Schauen wir uns die Funktion mal an, die wir dazu bauen müssen:
Delphi-Quellcode:
function FibonacciNumbers: IEnumerable<UInt64>;
begin
  Result := TEnumerable<UInt64>.Create(
    procedure
    var
      a, b, c: UInt64;
    begin
      a := 0;
      b := 1;
      Yield(a);
      Yield(b);
      repeat
        c := a + b;
        a := b;
        b := c;
        Yield(c);
      until c > High(UInt64) div 2;
    end);
end;
Als erstes fällt auf, dass die Funktion ein Interface vom Typ IEnumerable<UInt64> zurück gibt. Aha, deshalb kann man also mit der for-in Schleife darüber laufen und sogar weitere Funktionen aufrufen?!
Genau, und das Objekt, was dahinter steckt erstellen wir in der Funktion und übergeben ihm eine anonyme Methode, welche die Daten bereit stellt.
Aber was ist dieses Yield?? Damit kann man quasi jedesmal den Programmablauf innerhalb dieser anonymen Methode wieder abgeben. Dieser kehrt beim nächsten Zugriff auf .Next des Enumerators wieder an diese Stelle zurück. Dies wird intern über ein Fiber gemacht. Dabei habe ich mich an dieser Implementierung orientiert und das ganze noch erweitert.
Außerdem habe ich einige Helper Klassen erstellt um das einigen von .Net bekannte Verhalten der Enumerators dort nachzuempfinden.
Um das ganze zu benutzen muss die Generics.Enumerators ins Uses gepackt werden, die anderen Units müssen nur durch Suchpfad erreichbar sein.

Das ganze ist wie immer nicht im Großen und Ganzen durchgetestet, aber ich habe damit immerhin schon ein kleines Framework im Linq-To-SQL Stil realisiert.
Angehängte Dateien
Dateityp: zip Enumerators.zip (4,1 KB, 66x aufgerufen)
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:32 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz