Deferred execution in C#

我怕爱的太早我们不能终老 提交于 2019-12-13 11:55:02

问题


How could I implement my own deferred execution mechanism in C#?

So for instance I have:

string x = DoFoo();

Is it possible to perform some magic so that DoFoo does not execute until I "use" x?


回答1:


You can use lambdas/delegates:

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

Later you can invoke doit just like a method:

string x = doit();

I think the closest you can get is something like this:

Lazy<string> x = DoFoo;

string y = x; // "use" x

With a definition of Lazy<T> similar to this (untested):

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

Unfortunately, it seems that the compiler's type inferencing algorithms can't auto-infer the type of the Func<T> and so can't match it to the implicit conversion operator. We need to explicitly declare the delegate's type, which makes the assignment statements more verbose:

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



回答2:


One option is to use the Lazy<T> class, formerly from the parallel extensions library now a part of the .Net Framework 4.0.

  • Reference: http://msdn.microsoft.com/en-us/library/dd642331(VS.100).aspx

It allows you to delay process data in a thread aware manner.




回答3:


While it's somewhat dirty you could always use the yield keyword:

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



回答4:


Instead of passing a string x, pass a delegate that procures you a string

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



回答5:


Why not just not call 'DoFoo()' until you want to?

-- Edit

I mean, what do you mean "use"

For example, if you want it to be called when '.ToString()' called, you can always inherit the class and implement your function there (but this would be quite unintuitive IMHO).




回答6:


You pretty much describe LINQ in action. A linq query describes how to obtain the data, but data is retrieved (DoFunc is called) only when the query is iterated. Consider if you can change your design to accept IQueryable<string> where you need a string.



来源:https://stackoverflow.com/questions/1402923/deferred-execution-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!