Latente Ausführung in C #
-
05-07-2019 - |
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?
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
beziehtFunc<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
.