C# 3.0 C#lambda表达式与惰性求值

C# 3.0 C#lambda表达式与惰性求值,c#-3.0,lambda,lazy-evaluation,C# 3.0,Lambda,Lazy Evaluation,lambda表达式的一个优点是,只有在需要函数的结果时才需要对其求值 在以下(简单)示例中,文本函数仅在有编写器时计算: public static void PrintLine(Func<string> text, TextWriter writer) { if (writer != null) { writer.WriteLine(text()); } } 我们必须这样称呼它: PrintLine(() => "Some text"

lambda表达式的一个优点是,只有在需要函数的结果时才需要对其求值

在以下(简单)示例中,文本函数仅在有编写器时计算:

public static void PrintLine(Func<string> text, TextWriter writer)
{
    if (writer != null)
    {
        writer.WriteLine(text());
    }
}
我们必须这样称呼它:

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;
       }
}
公共类F
{
私有只读T值;
私有只读函数Func;
公共F(T值){this.value=value;}
公共F(Func Func){this.Func=Func;}
公共静态隐式运算符F(T值)
{
返回新的F(值);
}
公共静态隐式运算符F(Func Func)
{
返回新的F(func);
}
公共评估
{
返回this.func!=null?this.func():this.value;
}
}
现在我可以将函数定义为:

public static void PrintLine(F<string> text, TextWriter writer)
{
    if (writer != null)
    {
        writer.WriteLine(text.Eval());
    }
}
公共静态无效打印行(F文本,TextWriter)
{
if(writer!=null)
{
writer.WriteLine(text.Eval());
}
}

用一个函数或一个值来调用它。

这两个语句完全不同。一个是定义函数,另一个是语句。混淆语法要复杂得多

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

"SomeText" //this is a string

您可以使用重载:-

public static void PrintLine(string text, TextWriter writer)
{
    PrintLine(() => text, writer);
}

您可以在字符串上编写一个扩展方法来将其粘住。你应该能够写“一些文本”;让它为你工作


奇怪的是,几周前我对lambda表达式进行了一些惰性计算。

编译器非常擅长推断类型,但不擅长推断意图。关于C#3中所有新的语法糖,其中一个棘手的问题是,它们可能会导致编译器如何处理它们的混淆

以你的例子为例:

() => "SomeText"
编译器看到了这一点,并理解您打算创建一个匿名函数,该函数不接受任何参数,并返回System.String类型。这都是从你给它的lambda表达式推断出来的。实际上,您的lambda被编译为:

delegate {
    return "SomeText";
};
它是这个匿名函数的委托,您将它发送到
PrintLine
执行

它在过去一直很重要,但现在对于LINQ、lambdas、迭代器块、自动实现的属性,以及其他一些东西,最重要的是使用一种工具,比如在编译后查看代码,看看是什么真正使这些功能起作用。

我怀疑C#是否能够获得此功能,但事实并非如此。您所概述的是一种在C#中实现惰性参数求值的合适方法,它的编译可能与在D中非常相似,并且使用更纯的函数式语言


综上所述,四个额外的字符,加上可选的空白,对于正在成为一种多范式强类型语言的清晰的重载解析和表达能力来说,并不是一个特别大的代价。

不幸的是,丑陋的语法是C#的全部

更新中的“脏黑客”不起作用,因为它不会延迟字符串参数的计算:它们在传递给
操作符F(T值)
之前会被计算


PrintLine(()=>string.Join(“,”,names),myWriter)
PrintLine(string.Join(“,”,names),myWriter)
比较在第一种情况下,字符串仅在打印时才被连接;在第二种情况下,不管发生什么情况,字符串都是连接的:只有打印是有条件的。换句话说,评估一点也不懒惰。

这违背了目的。不管发生什么情况,都会对已定义的PrintLine重载的参数求值。在中添加lambda只会不必要地加深调用堆栈。不仅如此,还必须为n个参数创建2^n重载。我想我误解了OPs的需要。事实证明,添加一个重载实际上可能是正确的做法,尽管我认为我应该反转它们(让接受委托的调用接受值的调用,而不是相反)。在你的博客中,你说没有Func。系统如何?行动?我同意。在添加重载的情况下,(如果支持这样的快捷方式),就不可能分辨出区别。
delegate {
    return "SomeText";
};