擴充 Dynamic LINQ 支援查詢時 回傳指定型別

擴充 Dynamic LINQ 支援查詢時 回傳指定型別

最近在開發時遇到一個情境,需要動態決定Linq查詢的欄位清單,並回傳到指定的型別。

舉例,不使用Dynamic Linq的寫法

   1: List<SourceClass> list = new List<SourceClass>();
   2: var result = list.Select(a=>new TargetClass{ Id = a.No, Name = a.FullName);

改用Dynamic Linq 我改成以下寫法

   1: List<SourceClass> list = new List<SourceClass>();
   2: var result = list.AsQueryable().Select("new TargetClass(No as Id,FullName as Name)");

 

@@ 很不幸的 ,這樣是不會Work的

回頭Google了一下,然後去追Dynamic Linq 原始檔

修改步驟如下

 

Step 1 :

開啟Dynamic.cs

 

Step 2 :

先找到此區塊

   1: public Expression Parse(Type resultType)
   2: {            
   3:      int exprPos = token.pos;
   4:      ...
   5:      return expr;
   6: }

修改成

   1: private Type tmpResultType; //加入此行,用來暫存resultType
   2: public Expression Parse(Type resultType)
   3: {
   4:      tmpResultType = resultType; //加入此行,存入resultType
   5:      int exprPos = token.pos;
   6:      ...
   7:      return expr;
   8: }

 

Step 3 :

找到此區塊

   1: private Expression ParseNew()
   2: {
   3:     NextToken();
   4:     ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
   5:     ...
   6:     return Expression.MemberInit(Expression.New(type), bindings);
   7: }

修改成

   1: private Expression ParseNew()
   2: {
   3:      NextToken();
   4:      ...
   5:      NextToken();
   6:      Type type = tmpResultType ?? DynamicExpression.CreateClass(properties); //修改此行,直接設定要回傳的型別
   7:      MemberBinding[] bindings = new MemberBinding[properties.Count];
   8:      for (int i = 0; i < bindings.Length; i++)
   9:          bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
  10:      return Expression.MemberInit(Expression.New(type), bindings);
  11: }

 

Step 4 :

新增此區段

public static IQueryable Select(this IQueryable source, string selector, params object[] values)
{
     if (source == null) throw new ArgumentNullException("source");
     if (selector == null) throw new ArgumentNullException("selector");
     LambdaExpression lambda = System.Linq.Dynamic.DynamicExpression.ParseLambda(source.ElementType, typeof(TResult), selector, values);
        return source.Provider.CreateQuery(
           Expression.Call(
              typeof(Queryable), "Select",
              new Type[] { source.ElementType, typeof(TResult) },
              source.Expression, Expression.Quote(lambda)));
}

 

完工

 

 

最後使用方式

   1: List<SourceClass> list = new List<SourceClass>();
   2: var result = list.AsQueryable().Select<TargetClass>("new(No as Id,FullName as Name)");

就可以順利回傳指定型別囉~~~~

 

 

 

參考資料

Dynamic LINQ 讓 LINQ 的世界變的更美好

 




 


 

  • 如果您覺得這篇文章有幫助,請您幫忙推薦一下或按上方的""給予支持,非常感激
  • 歡迎轉載,但請註明出處
  • 文章內容多是自己找資料學習到的心得,如有不詳盡或錯誤的地方,請多多指教,謝謝