C # Przekształcenie magicznego ciągu w wyrażenie lambda
Mam zestaw metod rozszerzeń, które pozwalają na użycie magicznych łańcuchów w LINQOrderBy()
metody. Wiem, że pierwsze pytanie brzmi: dlaczego, ale jest częścią ogólnego repozytorium i ma na celu elastyczność, dzięki czemu łańcuchy mogą być wysyłane z interfejsu użytkownika i wykorzystywane bezpośrednio.
Mam to działa, jeśli przekażesz magiczny ciąg, który reprezentuje właściwość głównej jednostki, o którą pytasz, ale mam problem z uczynieniem go bardziej ogólnym, aby mógł obsłużyć wiele poziomów głębokiej magii. Na przykład:
IQueryable<Contact> contacts = GetContacts();
contacts.OrderByProperty("Name"); // works great
// can't figure out how to handle this
contacts.OrderByProperty("ContactType.Name");
Oto kod, który mam do tej pory:
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);
}
}
Jestem prawie pewien, że muszę podzielićpropertyName
w tym okresie, a następnie użyj tych części do zbudowania bardziej skomplikowanego wyrażenia, które obejmujeMemberExpression
a potem Własność, ale walczę. Każda pomoc lub wskazanie we właściwym kierunku będzie mile widziane.