Pregunta

¿Cómo podría implementar mi propio mecanismo de ejecución diferida en C #?

Entonces, por ejemplo, tengo:

string x = DoFoo();

¿Es posible realizar algo de magia para que DoFoo no se ejecute hasta que yo " use " x?

¿Fue útil?

Solución

Puede usar lambdas / delegados:

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

Más tarde puede invocar doit como un método:

string x = doit();

Creo que lo más cerca que puedes estar es algo como esto:

Lazy<string> x = DoFoo;

string y = x; // "use" x

Con una definición de Lazy<T> similar a esta (sin probar):

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;
    }
}

Desafortunadamente, parece que los algoritmos de inferencia de tipos del compilador no pueden inferir automáticamente el tipo de Func<T> y, por lo tanto, no pueden coincidir con el operador de conversión implícito. Necesitamos declarar explícitamente el tipo de delegado, lo que hace que las declaraciones de asignación sean más detalladas:

// 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);

Otros consejos

Una opción es usar la clase Lazy<T>, anteriormente de la biblioteca de extensiones paralelas que ahora forma parte de .Net Framework 4.0.

Le permite retrasar los datos del proceso de manera consciente.

Si bien está algo sucio, siempre puedes usar 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());
}

En lugar de pasar una cadena x , pase un delegado que le proporcione una cadena

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

¿Por qué no simplemente no llamar a 'DoFoo ()' hasta que lo desee?

- Editar

Quiero decir, ¿qué quieres decir con " usa "

Por ejemplo, si desea que se llame cuando se llame '.ToString ()', siempre puede heredar la clase e implementar su función allí (pero esto sería bastante poco intuitivo).

Describes más o menos LINQ en acción. Una consulta linq describe cómo obtener los datos, pero los datos se recuperan (se llama a DoFunc) solo cuando la consulta se repite. Considere si puede cambiar su diseño para aceptar IQueryable<string> donde necesita un string.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top