14

如何在 C# 中实现自己的延迟执行机制?

所以例如我有:

string x = DoFoo();

是否可以执行一些魔术,以便在我“使用”x 之前 DoFoo 不会执行?

4

6 回答 6

19

您可以使用 lambdas/委托:

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

稍后您可以doit像调用方法一样调用:

string x = doit();

我认为你能得到的最接近的是这样的:

Lazy<string> x = DoFoo;

string y = x; // "use" x

与此类似的定义Lazy<T>(未经测试):

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

不幸的是,编译器的类型推断算法似乎无法自动推断 the 的类型,Func<T>因此无法将其与隐式转换运算符匹配。我们需要显式声明委托的类型,这使得赋值语句更加冗长:

// 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);
于 2009-09-10T01:10:16.793 回答
6

一种选择是使用Lazy<T>该类,该类以前来自并行扩展库,现在是 .Net Framework 4.0 的一部分。

它允许您以线程感知的方式延迟处理数据。

于 2009-09-10T02:05:54.547 回答
4

虽然它有点脏,但您始终可以使用 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());
}
于 2009-09-10T01:33:32.520 回答
1

而不是传递一个字符串x,传递一个委托给你一个字符串

Func<String> fooFunc=()=>DoFoo();
于 2009-09-10T01:10:38.610 回答
0

为什么不直接调用 'DoFoo()' 直到你想调用?

- 编辑

我的意思是,你是什么意思“使用”

例如,如果您希望在调用 '.ToString()' 时调用它,则始终可以继承该类并在那里实现您的函数(但这很不直观,恕我直言)。

于 2009-09-10T01:10:09.903 回答
0

您几乎描述了 LINQ 的实际应用。一个 linq 查询描述了如何获取数据,但只有在迭代查询时才检索数据(调用 DoFunc)。考虑是否可以更改设计以接受IQueryable<string>需要string.

于 2009-09-10T01:33:29.010 回答