我想创建一个通过查询获取项目的存储库模式类。不幸的是,我需要将此查询从一个类解析为另一个类(Picture to ListItem)以将其发送到服务器(api)。所以我的代码应该如下所示:
public static void ConvertQuery(Expression<Func<Picture, object>> oldQuery)
{
Expression<Func<ListItem, object>> newQuery = convert(oldQuery);
}
并且,例如,我想通过如下所示的强制转换属性转换旧查询:
我找到了一些我可以投射属性的解决方案。但最大的问题是将一个属性转换为字典字段(item1.Filename到item2。[&#34; Filename&#34;])
更新
@nejcs
我已尝试使用您的解决方案,但不幸的是我有例外:
System.ArgumentException:&#39; ParameterExpression类型 &#39; Microsoft.SharePoint.Client.ListItem&#39;不能用于代表 类型&#39; CastExpression.Picture&#39;&#39;
的参数
财产&#34;项目&#34;负责字典值,但我认为转换存在问题。下面是stackTrace:
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType,Expression&amp; body,ReadOnlyCollection 1参数)at System.Linq.Expressions.Expression.Lambda [TDelegate](表达体, String name,Boolean tailCall,IEnumerable 1 parameters)at System.Linq.Expressions.Expression 1.Update(表达体, IEnumerable`1参数)at System.Linq.Expressions.ExpressionVisitor.VisitLambda [T](表达式1 节点) System.Linq.Expressions.Expression 1.Accept(ExpressionVisitor visitor) 在System.Linq.Expressions.ExpressionVisitor.Visit(表达式节点)
在CastExpression.Program.Main(String [] args)
我也知道表达式主体是怎样的
对于oldClassQuery:
Expression<Func<Picture, object>> oldQuery = x => x.FileName == "AS";
{x =&gt;转换((x.FileName ==&#34; AS&#34;))}
对于newClassQuery:
Expression<Func<ListItem, object>> newQuery = x => x["FileName"] == "AS";
{x =&gt;转换((x.get_Item(&#34; FileName&#34;)==&#34; AS&#34;)}}
答案 0 :(得分: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") });
}
}
}
}
然后您可以通过简单地实例化它并使用lambda表达式作为参数调用Visit
方法来使用它:
var visitor = new RewritingVisitor();
var newQuery = visitor.Visit(oldQuery);
编辑:
我忘记了一个小但相当重要的部分:如果更新了子表达式,默认情况下,访问者将在传递新值的表达式上调用update(或类似方法)。在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 body创建新的lambda。