2017-10-05 99 views
0

我想創建通過查詢獲取項目的存儲庫模式類。不幸的是我需要將這個查詢從一個類解析到另一個類(Picture to ListItem)以將其發送到服務器(api)。所以,我的代碼應該看起來像如下:將表達式<Func <XClass,object >>轉換爲表達式<Func <YClass,object >>

public static void ConvertQuery(Expression<Func<Picture, object>> oldQuery) 
    { 
     Expression<Func<ListItem, object>> newQuery = convert(oldQuery); 
    } 

而且,例如,我想舊的查詢通過編制屬性像下面轉換:

  • SomePicture.Id => SomeListItem.Id
  • SomePicture .FileName => SomeListItem [「FileName」]

我發現了一些解決方案,我可以投射屬性。但最大的問題是鑄造一個屬性字典場(item1.Filename ITEM2的。[「文件名」])

更新

@nejcs

我試圖使用你的解決方案但不幸的是我有例外:

System.ArgumentException:Microsoft.SharePoint.Client.ListItem「型 的ParameterExpression'不能用於典型的代表 參數e'CastExpression.Picture''

屬性「Item」負責字典值,但我認爲轉換存在問題。下面是堆棧跟蹤:

在System.Linq.Expressions.Expression.ValidateLambdaArgs(類型 delegateType,表達&體,ReadOnlyCollection 1個參數)在 System.Linq.Expressions.Expression.Lambda [TDelegate](式體, 字符串名稱,布爾尾調用,IEnumerable的1個參數)在 System.Linq.Expressions.Expression 1.Update(式體, IEnumerable`1參數)在 System.Linq.Expressions.ExpressionVisitor.VisitLambda [T](式1 node)at System.Linq.Expressions.Expression 1.Acept(ExpressionVisitor visitor) 在System.Linq.Expressions.ExpressionVisitor.Visit(Expression節點)
在CastExpression.Program.Main(字串[] args)

我也知道身體表達怎麼看起來像

對於oldClassQuery:

Expression<Func<Picture, object>> oldQuery = x => x.FileName == "AS"; 

{X =>轉換((x.FileName == 「AS」))}

對於newClassQuery:

Expression<Func<ListItem, object>> newQuery = x => x["FileName"] == "AS"; 

{X =>轉換((X。get_Item(「FileName」)==「AS」))}

+1

您的解決方案是使用'ExpressionVisitor'並手動重寫表達式樹。 –

+0

我更新了有關您收到的例外的答案。 – nejcs

回答

0

您正在尋找ExpressionVisitor。只需通過擴展此類並重寫適當的方法來創建自定義的方法,這會將子表達式從一種形式轉換爲另一種形式。

例如,對於變換部件的訪問,你會做這樣的事情(不完整):

public class RewritingVisitor : ExpressionVisitor 
{ 
    private readonly ParameterExpression p = Expression.Parameter(typeof(ListItem)); // create new parameter which will be referenced later 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     if (node.Type == typeof(Picture)) 
     { 
      return p; 
     } 
     return node; 
    } 

    protected override Expression VisitMember(MemberExpression node) 
    { 
     var rewritten = Visit(node.Expression); 
     if (rewritten == node.Expression) return node; 

     if (node.Expression != null && 
      node.Expression.Type == typeof(Picture) && 
      rewritten.Type == typeof(ListItem)) 
     { 
      if (node.Member.Name == "Id") 
      { 
       return Expression.MakeMemberAccess(
        rewritten, 
        typeof(ListItem).GetProperty("Id")); 
      } 
      else if (node.Member.Name == "FileName") 
      { 
       return Expression.MakeIndex(
        rewritten, 
        typeof(ListItem).GetProperty("Item"), // default indexer name 
        new[] { Expression.Constant("FileName") }); 
      } 
     } 
    } 
} 

然後,您可以通過簡單地將其實例化使用,並調用Visit法lambda表達式作爲參數:

var visitor = new RewritingVisitor(); 
var newQuery = visitor.Visit(oldQuery); 

編輯:

我忘了一個小但很重要的一條:如果子表達式更新,通過高清訪問者將調用更新(或類似的方法)表達式傳入新值。在lambda表達式的情況下,驗證邏輯需要與最初相同類型的表達式,當然這是不正確的。你必須手動構建新的lambda表達式進行走訪部分組成:

protected override Expression VisitLambda<T>(Expression<T> node) 
{ 
    var lambdaExpr = (LambdaExpression)node; 
    var rewrittenParameters = lambdaExpr.Parameters.Select(x => (ParameterExpression)Visit(x)).ToArray(); 
    var rewrittenBody = Visit(lambdaExpr.Body); 

    return Expression.Lambda(rewrittenBody, rewrittenParameters); 
} 

這是你的訪客,這需要建立從改寫參數和lambda體新拉姆達的關懷缺失的覆蓋。

+0

非常感謝您解決我的問題和這個問題的解釋:) – krawat10

相關問題