14

C# で独自の遅延実行メカニズムを実装するにはどうすればよいですか?

たとえば、私は持っています:

string x = DoFoo();

x を「使用」するまで DoFoo が実行されないように魔法を実行することは可能ですか?

4

6 に答える 6

19

ラムダ/デリゲートを使用できます:

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

残念ながら、コンパイラの型推論アルゴリズムは型を自動推論できない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

1 つのオプションは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 に答える