1

我最近为客户端实现了 IronRuby Web 服务应用程序,以替换现有的 C# .NET DLL。客户忘记提及的是,与此同时,他们实现了一个新版本的 DLL,带有一个基于 lambda 表达式的新 API。并确保所有调用(数千个 :( )都使用新语法。所以现在我需要实现一个替换 .NET DLL,它接收 Func/Actions 并在远程服务器上执行它们。

现在我是一名 Ruby/Perl 专家,对高级 .NET 知之甚少。我不太明白表达式和lambas之间的区别。我知道 LINQ to SQL 可以在远程 SQL 服务器上执行表达式。它也可以执行 lambdas 吗?我可以在我的场景中使用相同的方法(无论是什么方法)吗?

通常欢迎任何指针/想法/解决方案。

谢谢,弗雷德里克

4

1 回答 1

2

我不确定你到底要什么;但至少我可以尝试提供一些关于Expressionlambda 函数和 lambda 函数的区别的见解,它们都是主流 .NET 语言(C#、VB.NET)的语言特性。


基本上,lambda 函数是一个匿名(未命名)函数,可以在另一个函数的范围内声明。在 C#(语言版本 3)中,它会这样声明:

   ( 参数列表 函数体) => 

例如:

void Foo()
{
    // two equivalent lambda functions with one double parameter 'x' each:
    var square = (double x) => x * x;
    var square2 = (double x) => { return x * x; };

    // lambda function that doesn't take any arguments:
    var doSomething = () => { Console.WriteLine("Hello."); }
}

(请注意,egsquare不是 lambda 函数的名称,而是引用它的变量的名称。lambda 函数本身没有该方法的任何名称void Foo()!)

C# 版本 2 已经可以实现非常相似的东西,称为匿名委托

delegate(double x) { return x * x; }  // is equivalent to: (double x) => x * x

使用 LINQ(在命名空间中)将表达式System.Linq.Expressions添加到 .NET 。基本上,它们是简单的数据结构,以抽象语法树(AST) 的形式描述任何可以用 C# 或 VB.NET 表示的计算。举个例子:

// case 1. IEnumerable<int>:
IEnumerable<int> xs = ...;
IEnumerable<int> queryXs = from x in xs where x > 0 select x;

// case 2. IQueryable<int>:
IQueryable<int>  ys = ...;
IEnumerable<int> queryYs = from y in ys where y > 0 select y;

这两个查询是相同的,除了ys是 typeIQueryable<int>而不是IEnumerable<int>. C#编译器会将上述两个查询翻译成不同的代码,即:

// case 1. IEnumerable<int>:
IQueryable<int> xs = ...;
IEnumerable<int> queryXs = xs.Where<int>(delegate (int x) { return x > 0; });

// case 2. IQueryable<int>:
IEnumerable<int> ys = ...;
ParameterExpression yParameter = Expression.Parameter(typeof(int), "y");
IEnumerable<int> queryYs.Where<int>(
    Expression.Lambda<Func<int, bool>>(
        Expression.GreaterThan(
            yParameter,
            Expression.Constant(0, typeof(int))),
        new ParameterExpression[] { yParameter }));

如果您研究后者,您会看到对于 的查询IQueryable<int>,编译器已将解析后的查询输出为描述查询的数据结构。另一方面,对于针对 的查询IEnumerable<int>,它只输出执行查询的代码。事实证明,编译器具有特殊的魔力,仅使用类型生成它已解析为表达式树的内容。IQueryable<T>

表达式,IQueryable<T>因此允许您在运行时分析查询并在实际运行之前对其执行优化和其他转换。这被 LINQ to SQL 大量使用,以编写智能、优化的 SQL 查询:

想象一下,数据库被要求提供某列x> 0 的所有行。

  • 如果数据库是一个IEnumerable<int>(我知道这确实简化了很多,但请耐心等待),则必须获取所有行,然后通过该.Where(delegate (int x) { ... })方法进行过滤。

  • 如果数据库是IQueryable<int>Expression则编译器的输出将在运行时进行分析并转换为 SQL 查询,以便它包含适当的WHERE x > 0子句并立即生成所需的行。


如果您对/解析表达式树的内部结构感兴趣,请查看 Bart De Smet 的深入博客系列,从IQueryable 故事 - LINQ to LDAP - 第 0 部分:简介开始。

于 2010-07-14T19:50:11.227 回答