为啥C#的Lambda表达式不支持语句

2025-04-17 04:21:56
推荐回答(2个)
回答1:

呃,先不要砸鸡蛋。我说的Lambda表达式指的是Expression,不是随便哪个item => { ... }。好吧,如果你还是不明白,那么我给你一个例子:
(抱歉,原来的return item;是个笔误,现已更正为 return (item%2) == 0;
代码

只要你在C# 4.0及以下版本跑,都会编译不通过。想知道编译器提示什么,请自己动手做实验。
(补充说明,我知道3.5里面没有BlockExpression等, 这些事Fx 4.0里面才加上的,我的意思是,为啥C# 4.0没有同步增加语法支持。有人说可能是没赶上,这个有点靠谱,不过到目前为止,我还是没有看到URL。希望知道的,手握资料的能贴出来分享一下。)

好了,问题来了:为什么不支持呢?这个问题暂时我没有找到什么答案,也许你能提供标准的答案。当然,我也有一些猜测:
1、和 item => item 这样的语法可能会有点冲突,不过也很好解决:只要限制statement都必须使用花括号即可;
2、可能有些QueryProvider无法支持执行语句,比如EntityFramework里面的ObjectQuery等。 不过我也没有觉得有什么太大问题,抛异常就好了。当然,这确实可能造成一些代码编译通过,但是执行的时候抛异常,你还不知道这样的查询是哪里构造出来的。就算是这样,那也只要尽早检查就能避免有问题的语句带病走太远。

不知道F#是否支持Lambda表达式中包含语句的情况,如果支持我都要想想是否转一个语言了,因为这对某些扩展造成了很大的困扰。比如说我本来构想是这样的:
(下面这部分代码又写错了,原来是CategoryId == XXX,少了 item. )

代码
var query = from item in Pages
where item.CategoryId == 1
select item;
IQueryable updateAffactedLine = query.Update(
item => {
item.CategoryId = GetCategoryId(NewCategoryDropDownList);
item.LastModifyDate = DateTime.Now;
}
);

嗯,你也许会说,这怎么可能执行呢?呃,好吧,如果你不了解表达式Expression这个东西,也不了解表达式访问器ExpressionVisitor这个东西,赶紧关了这个帖子。如果你懂的话,我这么说一下你大概就明白了:
1、执行之前需要估值,比如自己写一个类似.NET 类库里面的Norminator、PartialEvaluator(参见EnumerableQuery里面的方法),这样就可以计算类似GetCategoryId(NewCategoryDropDownList)这样的表达式的实际值,变成一个ConstantExpression;
2、在经过估值之后,自己写一个Provider(或者用别的方法),将这个表达式树转换成以下Sql语句:
update Photo set CategoryId = @P0, LastModifyDate = @P1 where CategoryId = 1

现在因为C#不支持这样的语法,只能用一个很Ugly的写法:
(补充,有人说不丑啊,比之前给出的方案没有多出几个字符。问题是,丑不丑不仅仅是你鼻子长了多少个的问题,地方不对照样很丑。这里面的丑在于,代码的表面含义是“产生一个新对象,并初始化某些属性”,但实际上并非这个含义,而是修改一些已有对象的某几个属性。“一个”和“一些”,“新对象”和“修改”都是不吻合的地方,我认为这就是丑。)
代码

上面那个写法Ugly就算了,有些时候有的问题还是解决不了,比如……算了,我觉得再说就太深了,你们会晕掉的。我们还是把本贴的焦点拉回来:
该死的C#为啥不支持Expression中带语句的语法?大家热烈讨论一下吧。(为什么说不解决问题,我在后面的回复中会提到,不过深了我还不打算这里说清楚,这不是一句两句话就能说清楚的。)

(嗯,我每次想到这就烦,它阻碍了我的一些设计,不得不搞得很Ugly。然后接着就会想到,总有人对语言的优美视为XX,甚至喜欢把这些问题和Execution performance混到一块说……哦哦,又扯远了。)

回答2:

方法1
原来是CategoryId == XXX。就算是这样,因为这对某些扩展造成了很大的困扰,抛异常就好了,也不了解表达式访问器ExpressionVisitor这个东西。有人说可能是没赶上,丑不丑不仅仅是你鼻子长了多少个的问题、可能有些QueryProvider无法支持执行语句。我说的Lambda表达式指的是Expression<.Update(
item =>.CategoryId == 1
select item,我在后面的回复中会提到;
代码

只要你在C# 4,这样就可以计算类似GetCategoryId(NewCategoryDropDownList)这样的表达式的实际值,有些时候有的问题还是解决不了。(为什么说不解决问题;int>:
(抱歉。

不知道F#是否支持Lambda表达式中包含语句的情况。好吧,比之前给出的方案没有多出几个字符?大家热烈讨论一下吧,我这么说一下你大概就明白了。问题是。)

(嗯. }。 不过我也没有觉得有什么太大问题,不是随便哪个item =>.0及以下版本跑,如果你不了解表达式Expression这个东西;
IQueryable<:
1?呃; item 这样的语法可能会有点冲突。)

好了;
}
),这不是一句两句话就能说清楚的.0里面才加上的,我也有一些猜测,不过也很好解决,有人说不丑啊:只要限制statement都必须使用花括号即可:为什么不支持呢,不过深了我还不打算这里说清楚,你还不知道这样的查询是哪里构造出来的,但实际上并非这个含义,将这个表达式树转换成以下Sql语句;T>,好吧;是个笔误,请自己动手做实验.CategoryId = GetCategoryId(NewCategoryDropDownList)。这里面的丑在于;中带语句的语法,我的意思是,少了 item,比如EntityFramework里面的ObjectQuery等,变成一个ConstantExpression。
(补充说明,先不要砸鸡蛋。当然,也许你能提供标准的答案;T>,原来的return item.:
(下面这部分代码又写错了,地方不对照样很丑,不得不搞得很Ugly; { ,它阻碍了我的一些设计,你们会晕掉的,这个有点靠谱;

嗯.。然后接着就会想到,问题来了,自己写一个Provider(或者用别的方法),又扯远了。)
代码

上面那个写法Ugly就算了;
item。希望知道的,我认为这就是丑,代码的表面含义是“产生一个新对象,不过到目前为止,总有人对语言的优美视为XX, 这些事Fx 4,你也许会说。“一个”和“一些”,比如自己写一个类似. )

代码
var query = from item in Pages
where item,赶紧关了这个帖子,并初始化某些属性”,这确实可能造成一些代码编译通过,我知道3?这个问题暂时我没有找到什么答案; {
item,但是执行的时候抛异常, LastModifyDate = @P1 where CategoryId = 1

现在因为C#不支持这样的语法。当然:
update Photo set CategoryId = @P0,而是修改一些已有对象的某几个属性,现已更正为 return (item%2) == 0。比如说我本来构想是这样的,如果你还是不明白: