繁体   English   中英

转换表达式 <Func<XClass, object> &gt;表达 <Func<YClass, object> &gt;

[英]Convert Expression<Func<XClass, object>> to Expression<Func<YClass, object>>

我想创建通过查询获取项目的存储库模式类。 不幸的是,我需要将此查询从一个类解析到另一个类(从图片到ListItem),以将其发送到服务器(API)。 所以我的代码应如下所示:

    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。[“ Filename”])

更新资料

@nejcs

我尝试使用您的解决方案,但不幸的是我有例外:

System.ArgumentException:类型'Microsoft.SharePoint.Client.ListItem'的ParametersExpression不能用于类型'CastExpression.Picture'的委托参数

属性“ Item”负责字典值,但是我认为转换存在问题。 以下是stackTrace:

在System.Linq.Expressions.Expression.ValidateLambdaArgs(类型委托类型,表达式和主体,ReadOnlyCollection 1参数)在System.Linq.Expressions.Expression.Lambda [TDelegate](系统处的表达式主体,字符串名称,布尔值tailCall,IEnumerable 1参数) .Linq.Expressions.Expression 1.在System.Linq.Expressions.Expression 1.Update(Expression body,IEnumerable`1参数)在System.Linq.Expressions.Expression 1.Update(Accept(ExpressionVisitor visitor) )在System.Linq.Expressions.ExpressionVisitor.Visit(Expression节点)
在CastExpression.Program.Main(String [] args)

我也知道表情主体的样子

对于oldClassQuery:

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

{x => Convert((x.FileName ==“ AS”))}

对于newClassQuery:

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

{x => Convert((x.get_Item(“ FileName”)==“ AS”))}

您正在寻找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主体创建新的lambda。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM