Pergunta

Como eu poderia implementar o meu próprio mecanismo de execução diferida no C #?

Assim, por exemplo eu tenho:

string x = DoFoo();

É possível executar um pouco de magia para que DoFoo não é executado até que eu "utilização" x?

Foi útil?

Solução

Você pode usar lambdas / delegados:

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

Mais tarde, você pode invocar doit apenas como um método:

string x = doit();

Eu acho que o mais próximo que você pode obter é algo como isto:

Lazy<string> x = DoFoo;

string y = x; // "use" x

Com uma definição de Lazy<T> semelhante a esta (não testado):

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

Infelizmente, parece que o tipo do compilador algoritmos de inferência não pode auto-inferir o tipo do Func<T> e assim não pode combiná-lo com o operador de conversão implícita. Precisamos declarar explicitamente o tipo do delegado, o que torna as instruções de atribuição mais detalhado:

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

Outras dicas

Uma opção é usar a classe Lazy<T>, anteriormente a partir da biblioteca de extensões paralela agora uma parte do .NET Framework 4.0.

Ele permite que você atrasar processar dados de forma consciente fio.

Embora seja um pouco suja você poderia sempre usar a palavra-chave rendimento:

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

Em vez de passar uma string x , passar um delegado que adquire você uma string

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

Por que não apenas não chamam de 'DoFoo ()' até que você deseja?

- Edit

Quer dizer, o que quer dizer "utilização"

Por exemplo, se você quer que ele seja chamado quando '.ToString ()' chamado, você sempre pode herdar a classe e implementar a sua função lá (mas isso seria IMHO bastante intuitiva).

Você praticamente descrever LINQ em ação. Uma consulta linq descreve como obter os dados, mas os dados são recuperados (DoFunc é chamado) apenas quando a consulta é iterativo. Considere se você pode mudar seu projeto de aceitar IQueryable<string> onde você precisa de um string.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top