SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  263 随笔 :: 19 文章 :: 3009 评论 :: 74万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

呃,先不要砸鸡蛋。我说的Lambda表达式指的是Expression<T>,不是随便哪个item => { ... }。好吧,如果你还是不明白,那么我给你一个例子:

(抱歉,原来的return item;是个笔误,现已更正为 return (item%2) == 0; 

复制代码
代码
IQueryable<int> values = new int[]{1}.AsQueryable();
int last = 0;
var query 
= values.Where(
    item 
=> {
        last 
= item;
        Console.WriteLine(
"Last value ={0}", last);
        
return (item%2) == 0;
    }
);
var result 
= query.ToArray();
            
复制代码

 

只要你在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
<int> 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的写法:

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

复制代码
代码
var query = from item in Pages
    
where item.CategoryId == 1
    select item;
IQueryable
<int> updateAffactedLine = query.UpdateUgly(
    () 
=> new Page(){
        CategoryId 
= GetCategoryId(NewCategoryDropDownList),
        LastModifyDate 
= DateTime.Now,
     }
);
复制代码

 

上面那个写法Ugly就算了,有些时候有的问题还是解决不了,比如……算了,我觉得再说就太深了,你们会晕掉的。我们还是把本贴的焦点拉回来:

该死的C#为啥不支持Expression<T>中带语句的语法?大家热烈讨论一下吧。(为什么说不解决问题,我在后面的回复中会提到,不过深了我还不打算这里说清楚,这不是一句两句话就能说清楚的。)

 

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

 

(补充:事实就是如此,又有人来说Execution performance的事情了,问题是我这里压根没打算探讨这个问题。) 

 

 

 

posted on   Sumtec  阅读(6633)  评论(69编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
点击右上角即可分享
微信分享提示