C#在泛型類中,通過表達式樹構造lambda表達式


場景

最近對爬蟲的數據庫架構做調整,需要將數據遷移到MongoDB上去,需要重新實現一個針對MongoDB的Dao泛型類,好吧,動手開工,當實現刪除操作的時候問題來了。

我們的刪除操作定義如下:void Delete(TEntity entity)。TEntity是我們的泛型類。

而MongoDB官方驅動自帶的刪除操作是這樣的:


  
  
  
          
1
2
3
// 假設數據模型為已定義的Article
var query = Query<Article>.EQ(t => t.Id, id);
coll.Remove(query);

Dao操作的接口是不能修改的,這就要求我們必須實現以下操作:

  1. 獲取entity的Id值
  2. 構造lambda表達式用於獲取Id屬性

實現

對於第1個好辦,直接通過反射拿就可以了,至於第2個構造lambda表達式卻不知該如何下手了。

在網上查資料了解到C# Lambda表達式樹允許我們像處理數據(比如讀取,修改)一樣來處理Lambda表達式。。這就有方向了,研究了一下表達式樹的相關知識,歷經坎坷終於將其實現。

我用到的lambda表達式比較簡單,也容易構造,代碼中看注釋應該就明白了,代碼:


  
  
  
          
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
/// <summary>
/// 因為使用的Mongodb,每個數據模型必定包含Id屬性,通過Id屬性來刪除實體
/// </summary>
/// <param name="entity"></param>
public void Delete(TEntity entity)
{
    var coll = _db.GetCollection<TEntity>(typeof(TEntity).Name);
    if (entity == null)
    {
        return;
    }
    ObjectId id = (ObjectId)typeof(TEntity).GetProperty("Id").GetValue(entity, null);

    // 通過表達式樹構造lambda表達式{t => t.Id}
    // 構造調用目標t
    var target = Expression.Parameter(typeof(TEntity), "t");
    // 構造對t的屬性Id的表達式
    MemberExpression bodyExp = Expression.Property(
        target,
        "Id");

    // 構造完整的lambda表達式
    Expression<Func<TEntity, ObjectId>> selector =
        Expression.Lambda<Func<TEntity, ObjectId>>(bodyExp, new [] { target });

    // 使用泛型前的語句: Query<Article>.EQ(t => t.Id, id);
    var query = Query<TEntity>.EQ(selector, id);
    coll.Remove(query);
}

參考資料

  1. C# Lambda表達式樹淺談
  2. C#教程:lambda表達式轉換成表達式樹

用到的工具

之前都是直接使用lambda表示,而且用的還很Happy,今天遇到的問題,讓我很傻眼,基礎還得鞏固啊。今天也是第一次調試lambda表達式,用到了Expression Tree Visualizer for VS 2010這個小工具。在項目調試過程中可以比較直觀的查看編譯好的lambda表達式。

安裝和使用方法,請參見:在Visual Studio 2010設置Expression Tree Visualizer


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM