为了账号安全,请及时绑定邮箱和手机立即绑定

在表达式中使用 ExpandoObject 代替原始实体

在表达式中使用 ExpandoObject 代替原始实体

C#
湖上湖 2023-09-24 16:20:30
我有这样的表达:Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";该表达式被传输到另一个不具有类型的应用程序MyEntity。为了能够执行表达式,我尝试将其中的类型替换为ExpandoObject使用ExpressionVistor. public class ReplaceToExpandoVisitor : ExpressionVisitor    {        ParameterExpression _parameter;        private Type _targetType = typeof(ExpandoObject);        public ReplaceToExpandoVisitor(ParameterExpression p2)        {            _parameter = p2;        }        protected override Expression VisitParameter(ParameterExpression node)        {            return _parameter;        }        protected override Expression VisitMember(MemberExpression node)        {            if (node.Member.MemberType != System.Reflection.MemberTypes.Property)                throw new NotSupportedException();            var memberName = node.Member.Name;            var propBinder = Binder.GetMember(CSharpBinderFlags.None,                memberName,                 GetType(),                 new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });            var inner = Visit(node.Expression);            // this is the right way, right?            var exp2 = Expression.Dynamic(propBinder, typeof(object), inner);            // I need to convert it right? Otherwise it will be of type object?            var propGetExpression = Expression.Convert(exp2, node.Type);            return propGetExpression;        }    }然而,该表达式在执行时返回 false。所以我想我没有正确访问 Expandoobject 中的“属性”。有人可以解释我做错了什么吗?
查看完整描述

1 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

我认为你使用活页夹使事情变得过于复杂。ExpandoObject实现IDictionary<string, object>接口,因此您可以替换x => x.FirstName == "Jonas"为x => x["FirstName"] == "Jonas"哪个应该更容易。另外,您必须重写VisitLambda, 来修改类型参数,否则转换将失败。


这是示例代码:


public class ReplaceToExpandoVisitor<TSource> : ExpressionVisitor

{

    private static readonly PropertyInfo ItemProperty = typeof(IDictionary<string, object>).GetProperty("Item");


    private readonly ParameterExpression _targetParameter = Expression.Parameter(typeof(ExpandoObject));


    protected override Expression VisitLambda<T>(Expression<T> node)

    {

        var body = this.Visit(node.Body);

        var parameters = node.Parameters.Select(this.Visit).Cast<ParameterExpression>();


        return Expression.Lambda(body, parameters);

    }


    protected override Expression VisitParameter(ParameterExpression node)

    {

        if (node.Type == typeof(TSource))

        {

            return this._targetParameter;

        }


        return node;

    }


    protected override Expression VisitMember(MemberExpression node)

    {

        if (node.Member.MemberType != MemberTypes.Property)

        {

            throw new NotSupportedException();

        }


        string memberName = node.Member.Name;


        return Expression.Convert(

            Expression.Property(

                this.Visit(node.Expression),

                ItemProperty, 

                Expression.Constant(memberName)

            ), 

            ((PropertyInfo)node.Member).PropertyType

        );

    }

}

用法:


Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";

Expression<Func<ExpandoObject, bool>> exp2 = (Expression<Func<ExpandoObject, bool>>) new ReplaceToExpandoVisitor<MyEntity>().Visit(exp);


dynamic obj = new ExpandoObject();

obj.FirstName = "Jonas";


bool result = exp2.Compile().Invoke(obj);


查看完整回答
反对 回复 2023-09-24
  • 1 回答
  • 0 关注
  • 122 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信