¿Cómo podría implementar mi propio mecanismo de ejecución diferida en C#?Ejecución diferida en C#
Así, por ejemplo, que tienen:
string x = DoFoo();
¿Es posible llevar a cabo un poco de magia para que DoFoo no se ejecuta hasta que "uso" x?
¿Cómo podría implementar mi propio mecanismo de ejecución diferida en C#?Ejecución diferida en C#
Así, por ejemplo, que tienen:
string x = DoFoo();
¿Es posible llevar a cabo un poco de magia para que DoFoo no se ejecuta hasta que "uso" x?
Puede utilizar lambdas/delegados:
Func<string> doit =() => DoFoo();
// - or -
Func<string> doit = DoFoo;
Más tarde se puede invocar doit
al igual que un método:
string x = doit();
creo que lo más cerca que se puede conseguir es algo como esto:
Lazy<string> x = DoFoo;
string y = x; // "use" x
Con una definición de Lazy<T>
similar a esto (no probado):
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;
}
}
Por desgracia, parece que los algoritmos de tipo de inferencia de que el compilador no puede auto-inferir el tipo de la Func<T>
y por lo tanto no pueden igualar a la operador de conversión implícito. Debemos declarar explícitamente el tipo del delegado, lo que hace que las instrucciones de asignación más prolija:
// 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);
¿Por qué no simplemente no llamar a 'DoFoo()' hasta que lo desee?
- Edit
Quiero decir, ¿qué quiere decir "utilizar"
Por ejemplo, si desea que se le llame cuando '.ToString()' se llama, siempre se puede heredar la clase e implementar su función allí (pero esto sería muy poco intuitivo en mi humilde opinión).
En lugar de pasar una cadena x, pasar a un delegado que procura una cadena
Func<String> fooFunc=()=>DoFoo();
Más o menos mucho describir LINQ en acción. Una consulta de linq describe cómo obtener los datos, pero se recuperan los datos (se llama a DoFunc) solo cuando se itera la consulta. Considere si puede cambiar su diseño para aceptar IQueryable<string>
donde necesita un string
.
Si bien es un poco sucia siempre se puede utilizar la palabra clave de rendimiento:
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());
}
Una opción es utilizar la clase Lazy<T>
, antes de la biblioteca de extensiones paralelas ahora una parte de .Net Framework 4.0.
Se le permite retrasar los datos de proceso de una manera consciente hilo.
Prefiero usar una clase de sistema para hacerlo. Sin embargo, la clase del sistema no implementa operador implícito, lo que me llevó a buscar por qué. Encontré [esto] (http://netvignettes.wordpress.com/2011/04/24/implicit-conversion-operators-are-bad/), que explica por qué. –
Pero, ¿cómo es "' string x = doit() '" cualquier cosa diferente de "' string x = DoFoo() '", aparte de la capa adicional de direccionamiento indirecto? – LukeH
No lo es. No pude leer la pregunta. Mejorará la respuesta en un segundo ... – dtb
Esto todavía llama a 'DoFoo()' antes de que x sea 'usado'. –