C#将魔术字符串转换为lambda表达式

时间:2013-07-21 07:37:22

标签: c# linq lambda expression

我有一组扩展方法,允许在LINQ OrderBy()方法中使用魔术字符串。我知道第一个问题将是原因,但它是通用存储库的一部分,并且具有灵活性,以便可以从UI发送字符串并直接使用。

如果你传入一个表示你正在查询的主要实体的属性的魔术字符串,我就可以工作了,但是我很难使它更通用,所以它可以处理多个级别的深魔术字符串。例如:

IQueryable<Contact> contacts = GetContacts();

contacts.OrderByProperty("Name"); // works great

// can't figure out how to handle this
contacts.OrderByProperty("ContactType.Name");

这是我到目前为止的代码:

public static class LinqHelpers
{
    private static readonly MethodInfo OrderByMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderBy" && method.GetParameters().Length == 2);
    private static readonly MethodInfo OrderByDescendingMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2);
    private static readonly MethodInfo ThenByMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "ThenBy" && method.GetParameters().Length == 2);
    private static readonly MethodInfo ThenByDescendingMethod = typeof(Queryable).GetMethods().Single(method => method.Name == "ThenByDescending" && method.GetParameters().Length == 2);

    public static IOrderedQueryable<TSource> ApplyOrdering<TSource>(IQueryable<TSource> source, string propertyName, MethodInfo orderingMethod)
    {
        var parameter = Expression.Parameter(typeof(TSource), "x");
        var orderByProperty = Expression.Property(parameter, propertyName);

        var lambda = Expression.Lambda(orderByProperty, new[] { parameter });

        var genericMethod = orderingMethod.MakeGenericMethod(new[] { typeof(TSource), orderByProperty.Type });

        return (IOrderedQueryable<TSource>)genericMethod.Invoke(null, new object[] { source, lambda });
    }

    public static IOrderedQueryable<TSource> OrderByProperty<TSource>(this IQueryable<TSource> source, string propertyName)
    {
        return ApplyOrdering(source, propertyName, OrderByMethod);
    }

    public static IOrderedQueryable<TSource> OrderByDescendingProperty<TSource>(this IQueryable<TSource> source, string propertyName)
    {
        return ApplyOrdering(source, propertyName, OrderByDescendingMethod);
    }

    public static IOrderedQueryable<TSource> ThenByProperty<TSource>(this IOrderedQueryable<TSource> source, string propertyName)
    {
        return ApplyOrdering(source, propertyName, ThenByMethod);
    }

    public static IOrderedQueryable<TSource> ThenByDescendingProperty<TSource>(this IOrderedQueryable<TSource> source, string propertyName)
    {
        return ApplyOrdering(source, propertyName, ThenByDescendingMethod);
    }
}

我很确定我需要在句点上拆分propertyName,然后使用这些部分构建一个更复杂的表达式,其中涉及MemberExpression然后属性但我正在努力。任何帮助或指向正确的方向将不胜感激。

1 个答案:

答案 0 :(得分:2)

我曾经写过我自己的谓词构建器类型的东西。我试图调整代码在这里发布。这将返回一个表达式来访问属性,并可用于构建更复杂的表达式 - 只需确保表达式的所有组件使用完全相同的param对象实例。

这不适用于代码。我认为这将需要一些轻微的调整,以使其适合您的使用。

这会输出param => (param.Child.IntProperty == 42)

您可以在where子句中使用predicate变量。假设您有一个名为List<Parent>的{​​{1}},您可以拨打parents

parents.Where(predicate)