2017-10-05 100 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

相关问题