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

我有这样的表达:

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 中的“属性”。


有人可以解释我做错了什么吗?


湖上湖
浏览 77回答 1
1回答

翻阅古今

我认为你使用活页夹使事情变得过于复杂。ExpandoObject实现IDictionary<string, object>接口,因此您可以替换x => x.FirstName == "Jonas"为x => x["FirstName"] == "Jonas"哪个应该更容易。另外,您必须重写VisitLambda, 来修改类型参数,否则转换将失败。这是示例代码:public class ReplaceToExpandoVisitor<TSource> : ExpressionVisitor{&nbsp; &nbsp; private static readonly PropertyInfo ItemProperty = typeof(IDictionary<string, object>).GetProperty("Item");&nbsp; &nbsp; private readonly ParameterExpression _targetParameter = Expression.Parameter(typeof(ExpandoObject));&nbsp; &nbsp; protected override Expression VisitLambda<T>(Expression<T> node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var body = this.Visit(node.Body);&nbsp; &nbsp; &nbsp; &nbsp; var parameters = node.Parameters.Select(this.Visit).Cast<ParameterExpression>();&nbsp; &nbsp; &nbsp; &nbsp; return Expression.Lambda(body, parameters);&nbsp; &nbsp; }&nbsp; &nbsp; protected override Expression VisitParameter(ParameterExpression node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (node.Type == typeof(TSource))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return this._targetParameter;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return node;&nbsp; &nbsp; }&nbsp; &nbsp; protected override Expression VisitMember(MemberExpression node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (node.Member.MemberType != MemberTypes.Property)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new NotSupportedException();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; string memberName = node.Member.Name;&nbsp; &nbsp; &nbsp; &nbsp; return Expression.Convert(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression.Property(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.Visit(node.Expression),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ItemProperty,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression.Constant(memberName)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((PropertyInfo)node.Member).PropertyType&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; }}用法: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);
打开App,查看更多内容
随时随地看视频慕课网APP