Frage

Wie kann ich meine eigenen verzögerte Ausführung Mechanismus in C # implementieren?

So zum Beispiel habe ich:

string x = DoFoo();

Ist es möglich, etwas Magie auszuführen, so dass DoFoo nicht ausgeführt, bis ich „Verwendung“ x?

War es hilfreich?

Lösung

Sie können lambdas / Delegierten verwenden:

Func<string> doit = () => DoFoo();
//  - or -
Func<string> doit = DoFoo;

Sie können später aufrufen doit wie eine Methode:

string x = doit();

Ich denke, die nächst Sie bekommen so etwas wie diese:

Lazy<string> x = DoFoo;

string y = x; // "use" x

Mit einer Definition von Lazy<T> ähnlich wie diese (nicht getestet):

public class Lazy<T>
{
    private readonly Func<T> func;
    private bool hasValue;
    private T value;

    public Lazy(Func<T> func)
    {
        this.func = func;
        this.hasValue = false;
    }

    public static implicit operator Lazy<T>(Func<T> func)
    {
        return new Lazy<T>(func);
    }

    public static implicit operator T(Lazy<T> lazy)
    {
        if (!lazy.hasValue)
        {
            lazy.value = lazy.func();
            lazy.hasValue = true;
        }
        return lazy.value;
    }
}

Leider scheint es, dass die Typenanalyse-Algorithmen können Compiler nicht den Typ des Func<T> Auto-schließen und so kann es nicht auf die implizite Konvertierung Operator entsprechen. Wir müssen explizit den Typ des Delegaten deklarieren, die die Zuweisungsanweisungen ausführlicher macht:

// none of these will compile...
Lazy<string> x = DoFoo;
Lazy<string> y = () => DoFoo();
Lazy<string> z = delegate() { return DoFoo(); };

// these all work...
Lazy<string> a = (Func<string>)DoFoo;
Lazy<string> b = (Func<string>)(() => DoFoo());
Lazy<string> c = new Func<string>(DoFoo);
Lazy<string> d = new Func<string>(() => DoFoo());
Lazy<string> e = new Lazy<string>(DoFoo);
Lazy<string> f = new Lazy<string>(() => DoFoo);

Andere Tipps

Eine Möglichkeit ist es, die Lazy<T> Klasse zu verwenden, die früher von der parallelen Erweiterungen Bibliothek jetzt einem Teil des .NET Framework 4.0.

Es ermöglicht Ihnen, Prozessdaten in einem Thread bewusst Weise zu verzögern.

Während es etwas schmutzig ist können Sie immer die Ausbeute Schlüsselwort verwenden:

public IEnumerable<int> DoFoo() {
   Console.WriteLine("doing foo");
   yield return 10;
}

[Test]
public void TestMethod()
{
    var x = DoFoo();
    Console.WriteLine("foo aquired?");
    Console.WriteLine(x.First());
}

Statt einen String zugeben x , übergeben Sie einen Delegaten, dass Sie eine Zeichenfolge

bezieht
Func<String> fooFunc=()=>DoFoo();

Warum nicht einfach nicht 'DoFoo ()' aufrufen, bis Sie wollen?

- Bearbeiten

Ich meine, was meinst du mit "Verwendung"

Zum Beispiel, wenn Sie es wollen aufgerufen werden, wenn ‚.ToString ()‘ genannt, können Sie immer die Klasse erben und Ihre Funktion umsetzen werden (aber das wäre ganz unintuitive IMHO).

Sie beschreiben ziemlich LINQ in Aktion. Eine Linq-Abfrage beschreibt, wie die Daten zu erhalten, aber die Daten abgerufen werden nur (DoFunc genannt wird), wenn die Abfrage iteriert. Überlegen Sie, ob Sie Ihr Design IQueryable<string> zu akzeptieren ändern wo Sie brauchen eine string.

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