构建通用表达树.NET Core

问题描述 投票:1回答:1

您好,我知道这可能是重复的社区。

How do I dynamically create an Expression<Func<MyClass, bool>> predicate from Expression<Func<MyClass, string>>?

https://www.strathweb.com/2018/01/easy-way-to-create-a-c-lambda-expression-from-a-string-with-roslyn/

How to create a Expression.Lambda when a type is not known until runtime?

显然资源太多。

尽管我还是很困惑。有人可以提供下面代码中发生的情况的更清晰图片。我在下面提供了一些评论,以帮助我理解。

private Expression<Func<T, bool>> ParseParametersToFilter<T>(string parameters)
        {
            Expression<Func<T, bool>> finalExpression = Expression.Constant(true); //Casting error

            if (string.IsNullOrEmpty(parameters))
                return finalExpression;

            string[] paramArray = parameters.Split(","); //parameters is one string splitted with commas
     ParameterExpression argParam = Expression.Parameter(typeof(T), "viewModel"); //Expression Tree

            foreach (var param in paramArray)
        {
            var parsedParameter = ParseParameter(param);
            if (parsedParameter.operation == Operation.None)
                continue; // this means we parsed incorrectly we TODO: Better way for error handling

            //Property might be containment property e.g T.TClass.PropName
            Expression nameProperty = Expression.Property(argParam, parsedParameter.propertyName);
            //Value to filter against
            var value = Expression.Constant(parsedParameter.value);
            Expression comparison;
            switch (parsedParameter.operation)
            {   //Enum
                case Operation.Equals:
                    comparison = Expression.Equal(nameProperty, value);
                    break;
                    //goes on for NotEquals, GreaterThan etc
            }
            finalExpression = Expression.Lambda(comparison, argParam);// Casting error
        }

        return finalExpression;
    }

以上显然不起作用。

此返回到linq查询,就像IEnumerable<SomeModel>.Where(ParseParametersToFilter.Compile())

我了解我的错误是强制性错误。我该如何解决?

@@ Jeremy Lakeman回答后,我更新了代码,使其看起来像这样。尽管我使用的ViewModel非常复杂。最后,我提供了一个小预览。

private Expression<Func<T, bool>> ParseParametersToFilter<T>(string parameters)
        {
            Expression<Func<T, bool>> finalExpression = t => true;

            if (string.IsNullOrEmpty(parameters))
                return finalExpression;

            string[] paramArray = parameters.Split(","); //parameters is one string splitted with commas

            ParameterExpression argParam = Expression.Parameter(typeof(T), "viewModel"); //Expression Tree
            Expression body = Expression.Constant(true);

            foreach (var param in paramArray)
            {
                var parsedParameter = ParseParameter(param);
                if (parsedParameter.operation == Operation.None)
                    continue; // this means we parsed incorrectly TODO: Better way for error handling

                //Property might be containment property e.g T.TClass.PropName
                Expression nameProperty = Expression.Property(argParam, parsedParameter.propertyName);
                //Value to filter against
                var value = Expression.Constant(parsedParameter.value);

                switch (parsedParameter.operation)
                {   //Enum
                    case Operation.Equals:
                        body = Expression.AndAlso(body, Expression.Equal(nameProperty, value));
                        break;
                        //goes on for NotEquals, GreaterThan etc
                }
                body = Expression.AndAlso(body, argParam);
            }

            return Expression.Lambda<Func<T, bool>>(body, argParam);
        }

但是现在我得到以下异常

当我将状态作为属性参数传递时:

未为类型'model.StatusEnum'和'System.String'定义二进制运算符Equal。

当我传递User.FriendlyName参数时:

没有为类型'model.ReportViewModel'定义实例属性'User.FriendlyName'参数名称:propertyName

这是我的视图模型的样子!

public class ReportViewModel
{
    public StatusEnum Status {get;set;}
    public UserViewModel User {get;set;}
}

public enum StatusEnum
{
    Pending,
    Completed
}

public class UserViewModel
{
    public string FriendlyName {get;set;}
}
c# generics .net-core lambda expression-trees
1个回答
1
投票
因此,您试图将类似"a==1,b==3"的内容转换为viewModel => viewModel.a == 1 && viewModel.b == 3

我认为您已经很接近了,只需要添加&&(或||),并始终创建一个lambda;

© www.soinside.com 2019 - 2024. All rights reserved.