為啥C#的Lambda運算式不支援語句?(無答案,你來回答。)

來源:互聯網
上載者:User

呃,先不要砸雞蛋。我說的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的事情了,問題是我這裡壓根沒打算探討這個問題。) 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.