Domanda

Come potrei implementare il mio meccanismo di esecuzione differita in C #?

Quindi ad esempio ho:

string x = DoFoo();

È possibile eseguire un po 'di magia in modo che DoFoo non venga eseguito fino a quando " usa " x?

È stato utile?

Soluzione

Puoi usare lambdas / delegates:

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

Successivamente puoi invocare doit proprio come un metodo:

string x = doit();

Penso che il più vicino che puoi ottenere sia qualcosa del genere:

Lazy<string> x = DoFoo;

string y = x; // "use" x

Con una definizione di Lazy<T> simile a questa (non testato):

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

Sfortunatamente, sembra che gli algoritmi di inferenza del tipo del compilatore non possano inferire automaticamente il tipo di Func<T> e quindi non possano corrispondere all'operatore di conversione implicito. Dobbiamo dichiarare esplicitamente il tipo di delegato, il che rende le dichiarazioni di assegnazione più dettagliate:

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

Altri suggerimenti

Un'opzione è usare la classe Lazy<T>, precedentemente dalla libreria di estensioni parallele ora parte di .Net Framework 4.0.

Ti consente di ritardare i dati di processo in modo consapevole del thread.

Anche se è un po 'sporco, puoi sempre usare la parola chiave yield:

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

Invece di passare una stringa x , passa un delegato che ti procura una stringa

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

Perché non chiamare semplicemente 'DoFoo ()' fino a quando non lo desideri?

- Modifica

Voglio dire, cosa intendi con " usa "

Ad esempio, se vuoi che venga chiamato quando viene chiamato '.ToString ()', puoi sempre ereditare la classe e implementare lì la tua funzione (ma questo sarebbe IMHO abbastanza non intuitivo).

Descrivi praticamente LINQ in azione. Una query linq descrive come ottenere i dati, ma i dati vengono recuperati (viene chiamato DoFunc) solo quando la query viene ripetuta. Considera se puoi cambiare il tuo design per accettare IQueryable<string> dove è necessario un string.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top