Método de extensão para classificar uma lista dentro de um objeto pai
Pergunta
public class Person
{
public string name { get; set; }
public Email email { get; set; }
}
public class Email
{
public string desc { get; set; }
}
public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression, bool desc)
{
var param = Expression.Parameter(typeof(T), string.Empty);
try
{
var property = Expression.Property(param, sortExpression);
var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);
if (desc)
{
return source.AsQueryable<T>().OrderByDescending<T, object>(sortLambda);
}
return source.AsQueryable<T>().OrderBy<T, object>(sortLambda);
}
catch (ArgumentException)
{
return source;
}
}
List<Person> vet = new List<Person>();
Person p = new Person { name = "aaa", email = new Email { desc = "bbb@aaa.com" } };
Person pp = new Person { name = "bbb", email = new Email { desc = "aaa@aaa.com" } };
vet.Add(p);
vet.Add(pp);
vet.Sort("name",true); //works
vet.Sort("email.desc",true) // doesnt work
alguém pode me ajudar?
Solução
Se você quiser este olhar funcionalidade em um artigo de ScottGu na Biblioteca Linq dinâmico . Eu acredito que ele vai fazer o que quiser.
Enquanto Lambda são do tipo seguro há momentos em que você pode querer gerar em tempo real a consulta ao invés de ter todas as combinações possíveis que um usuário pode classificar por exemplo.
Editar
Eu fixo o seu método. Basicamente, você precisa criar uma expressão para cada acesso de membro.
public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression, bool desc)
{
var param = Expression.Parameter(typeof(T), string.Empty);
try
{
var fields = sortExpression.Split('.');
Expression property = null;
Expression parentParam = param;
foreach (var field in fields)
{
property = Expression.Property(parentParam, field);
parentParam = property;
}
var sortLambda =
Expression.Lambda<Func<T, object>>(
Expression.Convert(property, typeof(object)), param);
if (desc)
{
return source.AsQueryable<T>().
OrderByDescending<T, object>(sortLambda);
}
return source.AsQueryable<T>().
OrderBy<T, object>(sortLambda);
}
catch (ArgumentException)
{
throw;
}
}
Outras dicas
Você pode querer pensar sobre um outro método que leva um comparador objeto personalizado para fazer a comparação. Você poderia, então, escrever um comparador personalizado para a pessoa que os compara com base em seus endereços de email.