8

ラムダ式の利点の 1 つは、結果が必要な場合にのみ関数を評価する必要があることです。

次の (単純な) 例では、テキスト関数はライターが存在する場合にのみ評価されます。

public static void PrintLine(Func<string> text, TextWriter writer)
{
    if (writer != null)
    {
        writer.WriteLine(text());
    }
}

残念ながら、これによりコードの使用が少し見苦しくなります。次のような定数または変数で呼び出すことはできません

PrintLine("Some text", Console.Out);

このように呼び出す必要があります:

PrintLine(() => "Some text", Console.Out);

コンパイラは、渡された定数からパラメーターなしの関数を「推測」できません。C# の将来のバージョンでこれを改善する計画はありますか、それとも何か不足していますか?

アップデート:

私は自分で汚いハックを見つけました:

    public class F<T>
    {
       private readonly T value;
       private readonly Func<T> func;

       public F(T value) { this.value = value; }
       public F(Func<T> func) {this.func = func; }

       public static implicit operator F<T>(T value)
       {
            return new F<T>(value);
       }

       public static implicit operator F<T>(Func<T> func)
       {
           return new F<T>(func);
       }

       public T Eval()
       {
           return this.func != null ? this.func() : this.value;
       }
}

これで、関数を次のように定義できます。

public static void PrintLine(F<string> text, TextWriter writer)
{
    if (writer != null)
    {
        writer.WriteLine(text.Eval());
    }
}

関数または値の両方で呼び出します。

4

7 に答える 7

3

C# にこの機能があるとは思えませんが、Dにはあります。あなたが概説したことは、C#で遅延引数評価を実装する適切な方法であり、おそらくlazyDやより純粋な関数型言語と非常によく似た方法でコンパイルされます。

すべてのことを考慮すると、4 つの余分な文字とオプションの空白は、明確なオーバーロードの解決と、マルチパラダイムの強力な型付け言語になりつつある言語での表現力のために支払う、非常に大きな代償ではありません。

于 2009-01-05T20:19:00.807 に答える
2

コンパイラは型の推論は得意ですが、意図の推論は得意ではありません。C# 3 のすべての新しいシンタックス シュガーに関するトリッキーな点の 1 つは、コンパイラが正確に何を行うかについて混乱を招く可能性があることです。

あなたの例を考えてみましょう:

() => "SomeText"

コンパイラはこれを見て、パラメーターをとらず、System.String 型を返す無名関数を作成しようとしていることを認識します。これはすべて、指定したラムダ式から推測されます。実際には、ラムダは次のようにコンパイルされます。

delegate {
    return "SomeText";
};

実行のために送信するのは、この匿名関数へのデリゲートですPrintLine

過去には常に重要でしたが、LINQ、ラムダ、イテレータ ブロック、自動的に実装されたプロパティなど、 .NET Reflectorなどのツールを使用して、コンパイル後にコードを確認することが最も重要になっています。これらの機能が実際に機能する理由を確認します。

于 2009-01-05T19:41:51.180 に答える
2

残念ながら、C# には醜い構文しかありません。

アップデートによる「ダーティ ハック」は機能しません。これは、文字列パラメータの評価を遅らせないためです。文字列パラメータは、に渡される前に評価されoperator F<T>(T value)ます。

比較PrintLine(() => string.Join(", ", names), myWriter)するとPrintLine(string.Join(", ", names), myWriter)、最初のケースでは、文字列は印刷される場合にのみ結合されます。2 番目のケースでは、文字列は何があっても結合されます。出力のみが条件付きです。つまり、評価はまったく怠惰ではありません。

于 2011-08-13T13:49:13.943 に答える
1

さて、これら2つのステートメントは完全に異なります。1 つは関数の定義で、もう 1 つはステートメントです。構文を混乱させると、さらに厄介になります。

() => "SomeText" //this is a function

"SomeText" //this is a string
于 2009-01-05T19:22:46.023 に答える
1

オーバーロードを使用できます:-

public static void PrintLine(string text, TextWriter writer)
{
    PrintLine(() => text, writer);
}
于 2009-01-05T19:23:02.480 に答える
1

String に拡張メソッドを記述して接着することができます。「Some text」.PrintLine(Console.Out); と記述できるはずです。そして、あなたのために仕事をさせてください。

奇妙なことに、私は数週間前にラムダ式の遅延評価をいじり、それについてブログに書きました

于 2009-01-05T19:23:19.517 に答える