Creating an expression from the string of a property name?

ぐ巨炮叔叔 提交于 2019-12-01 01:29:53

Something like this:

public static IQueryable<T> FilterObjectSet<T>(IQueryable<T> inputQuery, 
                                               Rule rule) where T : class
{
    var par = Expression.Parameter(typeof(T));

    var prop = Expression.PropertyOrField(par, rule.field);
    var propType = prop.Member.MemberType == System.Reflection.MemberTypes.Field ? 
                               ((FieldInfo)prop.Member).FieldType : 
                               ((PropertyInfo)prop.Member).PropertyType);

    // I convert the data that is a string to the "correct" type here
    object data2 = Convert.ChangeType(rule.data, 
                                      propType, 
                                      CultureInfo.InvariantCulture);

    var eq = Expression.Equal(prop, Expression.Constant(data2));
    var lambda = Expression.Lambda<Func<T, bool>>(eq, par);

    return inputQuery.Where(lambda);
}

If you need some explanation, you can ask. Note that this won't work on types that have special implicit conversions (like a MyString type that has an implicit conversion from string). This because Convert.ChangeType uses only the IConvertible interface.

Null handling for data is perhaps something else that should be handled.

Be aware that I'm not sure the Expression.PropertyOrField is handled by the various IQueryable<T> engines (LINQ-to-SQL and EF). I have only tested it with the AsQueryable() engine. If they don't "accept" it, you must split it in a Expression.Property or Expression.Field depending on what rule.field is.

A nearly equivalent version that doesn't use Expression.PropertyOrField:

public static IQueryable<T> FilterObjectSet<T>(IQueryable<T> inputQuery, 
                                               Rule rule) where T : class
{
    Type type = typeof(T);
    var par = Expression.Parameter(type);

    Type fieldPropertyType;
    Expression fieldPropertyExpression;

    FieldInfo fieldInfo = type.GetField(rule.field);

    if (fieldInfo == null)
    {
        PropertyInfo propertyInfo = type.GetProperty(rule.field);

        if (propertyInfo == null)
        {
            throw new Exception();
        }

        fieldPropertyType = propertyInfo.PropertyType;
        fieldPropertyExpression = Expression.Property(par, propertyInfo);
    }
    else
    {
        fieldPropertyType = fieldInfo.FieldType;
        fieldPropertyExpression = Expression.Field(par, fieldInfo);
    }

    object data2 = Convert.ChangeType(rule.data, fieldPropertyType);
    var eq = Expression.Equal(fieldPropertyExpression, 
                              Expression.Constant(data2));

    var lambda = Expression.Lambda<Func<T, bool>>(eq, par);
    return inputQuery.Where(lambda);
}

In the end I used a Dynamic Linq library I found on Guthrie's Blog:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Using this I was able to properly parse out and use the parameters I had built into the rules

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!