在表达式中使用 ExpandoObject 而不是原始实体

Using an ExpandoObject instead of the original entity in an expression

我的表达方式如下:

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

表达式被转移到另一个不具有类型 MyEntity.

的应用程序

为了能够执行表达式,我正在尝试使用 ExpressionVistor.

将其中的类型替换为 ExpandoObject
    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;
        }
    }

但是,表达式returns执行时为false。所以我想我没有正确访问 expandoobject 中的 "property"。

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

我认为您使用活页夹过于复杂了。 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);