he encontrado un ejemplo en el VS2008 Examples para la dinámica de LINQ que le permite utilizar una cadena de tipo SQL (por ejemplo OrderBy("Name, Age DESC"))
para ordenar Por desgracia, el método incluye sólo funciona en IQueryable<T>
;.. ¿Hay alguna manera para conseguir esta funcionalidad en IEnumerable<T>
dinámico LINQ OrdenarPor en IEnumerable <T>
Respuesta
tropezado este oldie ...
Para hacer esto sin la biblioteca dinámica LINQ, sólo necesita el código de la siguiente manera. Esto cubre los escenarios más comunes, incluidas las propiedades anidadas.
Para que funcione con IEnumerable<T>
puede agregar algunos métodos de contenedor que van a través de AsQueryable
- pero el siguiente código es el núcleo Expression
lógica necesaria.
Editar: se vuelve más divertido si usted quiere mezclar eso con dynamic
- aunque nota que dynamic
sólo se aplica a LINQ a Objetos (expresión-árboles de ORM etc realmente no pueden representar dynamic
consultas - MemberExpression
no lo admite). Pero aquí hay una manera de hacerlo con LINQ-to-Objects. Tenga en cuenta que la elección de Hashtable
se debe a la semántica de bloqueo favorables:
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.CompilerServices;
static class Program
{
private static class AccessorCache
{
private static readonly Hashtable accessors = new Hashtable();
private static readonly Hashtable callSites = new Hashtable();
private static CallSite<Func<CallSite, object, object>> GetCallSiteLocked(
string name)
{
var callSite = (CallSite<Func<CallSite, object, object>>)callSites[name];
if(callSite == null)
{
callSites[name] = callSite = CallSite<Func<CallSite, object, object>>
.Create(Binder.GetMember(
CSharpBinderFlags.None,
name,
typeof(AccessorCache),
new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(
CSharpArgumentInfoFlags.None,
null)
}));
}
return callSite;
}
internal static Func<dynamic,object> GetAccessor(string name)
{
Func<dynamic, object> accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
lock (accessors)
{
accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
if(name.IndexOf('.') >= 0) {
string[] props = name.Split('.');
CallSite<Func<CallSite, object, object>>[] arr
= Array.ConvertAll(props, GetCallSiteLocked);
accessor = target =>
{
object val = (object)target;
for (int i = 0; i < arr.Length; i++)
{
var cs = arr[i];
val = cs.Target(cs, val);
}
return val;
};
} else {
var callSite = GetCallSiteLocked(name);
accessor = target =>
{
return callSite.Target(callSite, (object)target);
};
}
accessors[name] = accessor;
}
}
}
return accessor;
}
}
public static IOrderedEnumerable<dynamic> OrderBy(
this IEnumerable<dynamic> source,
string property)
{
return Enumerable.OrderBy<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> OrderByDescending(
this IEnumerable<dynamic> source,
string property)
{
return Enumerable.OrderByDescending<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenBy(
this IOrderedEnumerable<dynamic> source,
string property)
{
return Enumerable.ThenBy<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenByDescending(
this IOrderedEnumerable<dynamic> source,
string property)
{
return Enumerable.ThenByDescending<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
static void Main()
{
dynamic a = new ExpandoObject(),
b = new ExpandoObject(),
c = new ExpandoObject();
a.X = "abc";
b.X = "ghi";
c.X = "def";
dynamic[] data = new[] {
new { Y = a },
new { Y = b },
new { Y = c }
};
var ordered = data.OrderByDescending("Y.X").ToArray();
foreach (var obj in ordered)
{
Console.WriteLine(obj.Y.X);
}
}
}
supongo que funcionaría a utilizar la reflexión para conseguir cualquier propiedad que desea ordenar en:?
IEnumerable<T> myEnumerables
var query=from enumerable in myenumerables
where some criteria
orderby GetPropertyValue(enumerable,"SomeProperty")
select enumerable
private static object GetPropertyValue(object obj, string property)
{
System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}
Tenga en cuenta que el uso de la reflexión es considerablemente más lento que acceder directamente al establecimiento, por lo el rendimiento woul d tiene que ser investigado.
hace esto, incluso ¿trabajo?orderby no quiere un valor sino un selector lamba/delegate (Func
Intenté este ejemplo antes de publicarlo, y sí, funciona. –
Esta solución funciona bien para la clasificación simple de propiedades individuales. –
Se podría añadir que:
public static IEnumerable<T> OrderBy(this IEnumerable<T> input, string queryString) {
//parse the string into property names
//Use reflection to get and sort by properties
//something like
foreach(string propname in queryString.Split(','))
input.OrderBy(x => GetPropertyValue(x, propname));
// I used Kjetil Watnedal's reflection example
}
La función GetPropertyValue
es de Kjetil Watnedal's answer
La cuestión sería ¿por qué? Cualquier tipo de este tipo arrojaría excepciones en tiempo de ejecución, en lugar de tiempo de compilación (como la respuesta de D2VIANT).
Si se trata de Linq a Sql y el orden es un árbol de expresiones, se convertirá en SQL para su ejecución de todos modos.
GetPropertyValue Mehotod se ejecutará para todos los elementos, es una mala solución. –
'OrderBy' no mantiene el orden anterior !! –
Encontré la respuesta. Puedo usar el método de extensión .AsQueryable<>()
para convertir mi lista a IQueryable, luego ejecutar el orden dinámico en contra de él.
Proporcione un ejemplo para el resto de nosotros. – MGOwen
he tropiezo esta pregunta en busca de Linq cláusulas múltiples OrdenarPor y tal vez esto era lo que el autor buscaba
Aquí es cómo hacer eso:
var query = pets.OrderBy(pet => pet.Name).ThenByDescending(pet => pet.Age);
+1 canceló el voto atrasado debido a la falta de explicación. También creo que el autor podría haber estado interesado en varios pedidos por bys. Incluso si dynamic * was * la palabra clave, no hay razón para votar abajo. –
Una solución alternativa utiliza la siguiente clase/interfaz. No es realmente dinámico, pero funciona.
public interface IID
{
int ID
{
get; set;
}
}
public static class Utils
{
public static int GetID<T>(ObjectQuery<T> items) where T:EntityObject, IID
{
if (items.Count() == 0) return 1;
return items.OrderByDescending(u => u.ID).FirstOrDefault().ID + 1;
}
}
Basándome en lo que otros han dicho. Descubrí que lo siguiente funciona bastante bien.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> input, string queryString)
{
if (string.IsNullOrEmpty(queryString))
return input;
int i = 0;
foreach (string propname in queryString.Split(','))
{
var subContent = propname.Split('|');
if (Convert.ToInt32(subContent[1].Trim()) == 0)
{
if (i == 0)
input = input.OrderBy(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenBy(x => GetPropertyValue(x, subContent[0].Trim()));
}
else
{
if (i == 0)
input = input.OrderByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
}
i++;
}
return input;
}
yo estaba tratando de hacer esto, pero tienen problemas con Kjetil Watnedal's solution porque yo no uso la sintaxis de LINQ en línea - Yo prefiero la sintaxis de estilo método. Mi problema específico era tratar de hacer una clasificación dinámica usando un IComparer
personalizado.
Mi solución terminó así:
Dada una consulta IQueryable así:
List<DATA__Security__Team> teams = TeamManager.GetTeams();
var query = teams.Where(team => team.ID < 10).AsQueryable();
Y dado un tiempo de ejecución argumento campo de clasificación:
string SortField; // Set at run-time to "Name"
Las dinámicas miradas OrdenarPor como ese:
query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField));
Y eso con un poco de método de ayuda llamada GetReflectedPropertyValue():
public static string GetReflectedPropertyValue(this object subject, string field)
{
object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
return reflectedValue != null ? reflectedValue.ToString() : "";
}
Una última cosa - he mencionado que quería que el OrderBy
de usar encargo IComparer
- porque quería hacer Natural sorting.
Para hacer eso, sólo altera el OrderBy
a:
query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField), new NaturalSortComparer<string>());
Ver this post para el código de NaturalSortComparer()
.
Recibí este error: LINQ to Entities no reconoce el método 'String GetReflectedPropertyValue (Object, String)', y este método no se puede traducir a una expresión de tienda. – Misi
aquí hay algo más que me pareció interesante. Si la fuente es un DataTable, puede utilizar la clasificación dinámica sin usar dinámico Linq
DataTable orders = dataSet.Tables["SalesOrderHeader"];
EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
orderby order.Field<DateTime>("OrderDate")
select order;
DataView view = query.AsDataView();
bindingSource1.DataSource = view;
de referencia: http://msdn.microsoft.com/en-us/library/bb669083.aspx (usando DataSetExtensions)
Aquí es una forma más de hacerlo mediante su conversión a un DataView:
DataTable contacts = dataSet.Tables["Contact"];
DataView view = contacts.AsDataView();
view.Sort = "LastName desc, FirstName asc";
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Acabo de tropezar con esta pregunta.
Usando aplicación ApplyOrder de Marc desde arriba, me dio una palmada en conjunto un método de extensión que se encarga de cadenas SQL-como como:
list.OrderBy("MyProperty DESC, MyOtherProperty ASC");
detalles se pueden encontrar aquí: http://aonnull.blogspot.com/2010/08/dynamic-sql-like-linq-orderby-extension.html
Cosas grandiosas, solo agregue una modificación de la siguiente manera para que el nombre de la propiedad no distinga entre mayúsculas y minúsculas: PropertyInfo pi = type.GetProperty (prop, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); –
Demasiado fácil y sin ningún tipo de complicación:
- Agregue
using System.Linq.Dynamic;
en la parte superior. - Use
vehicles = vehicles.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();
y de dónde obtuviste el 'System.Linq.Dynamic'? – Dementic
https://nuget.org/packages/System.Linq.Dynamic – tomfanning
Funciona al usar linq con MongoDB también. – soupy1976
Gracias a Maarten (Query a collection using PropertyInfo object in LINQ) Tengo esta solución:
myList.OrderByDescending(x => myPropertyInfo.GetValue(x, null)).ToList();
En mi caso, yo estaba trabajando en un "ColumnHeaderMouseClick" (WindowsForm) por lo que sólo se encontró la columna específica presionado y su PropertyInfo corresponsal:
foreach (PropertyInfo column in (new Process()).GetType().GetProperties())
{
if (column.Name == dgvProcessList.Columns[e.ColumnIndex].Name)
{}
}
O
PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First();
(asegúrese de tener sus nombres de las columnas que coinciden con las propiedades de los objetos)
Saludos
Después de mucho buscar esto funcionó para mí:
public static IEnumerable<TEntity> OrderBy<TEntity>(this IEnumerable<TEntity> source,
string orderByProperty, bool desc)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command,
new[] { type, property.PropertyType },
source.AsQueryable().Expression,
Expression.Quote(orderByExpression));
return source.AsQueryable().Provider.CreateQuery<TEntity>(resultExpression);
}
lista Convertir a IEnumerable o Iquerable , agregue el uso del espacio de nombres System.LINQ.Dynamic, luego puede mencionar los nombres de las propiedades en una secuencia separada por comas en el Método OrderBy que viene de forma predeterminada de System.LINQ.Dynamic.
Puede convertir IEnumerable en IQueryable.
items = items.AsQueryable().OrderBy("Name ASC");
var result1 = lst.OrderBy(a=>a.Name);// for ascending order.
var result1 = lst.OrderByDescending(a=>a.Name);// for desc order.
Esta respuesta es una respuesta a los comentarios que necesitan un ejemplo para la solución aportada por @John Sheehan - Runscope
Sírvanse proporcionar un ejemplo para el resto de nosotros.
en DAL (Data Access Layer),
La versión IEnumerable:
public IEnumerable<Order> GetOrders()
{
// i use Dapper to return IEnumerable<T> using Query<T>
//.. do stuff
return orders // IEnumerable<Order>
}
La versión IQueryable
public IQueryable<Order> GetOrdersAsQuerable()
{
IEnumerable<Order> qry= GetOrders();
//use the built-in extension method AsQueryable in System.Linq namespace
return qry.AsQueryable();
}
Ahora puede utilizar la versión IQueryable para enlazar, por ejemplo, Grid Ver en Asp.net y beneficiarse de la clasificación (no se puede ordenar usando la versión IEnumerable)
Utilicé Dapper como ORM y compilé la versión IQueryable y utilicé la clasificación en GridView en asp.net de manera fácil.
primera instalación dinámicos Herramientas -> Gestor de paquetes NuGet -> Gestor de paquetes de consola
install-package System.Linq.Dynamic
Añadir Espacio de nombresusing System.Linq.Dynamic;
Ahora puede utilizar OrderBy("Name, Age DESC")
- 1. IEnumerable OrdenarPor
- 2. La extensión de Marc Gravell dinámico LINQ OrdenarPor
- 3. IEnumerable <IEnumerable <T>> IEnumerable a <T> usando LINQ
- 4. LINQ OrdenarPor frente ThenBy
- 5. uso propio IComparer <T> con LINQ OrdenarPor
- 6. LINQ to SQL OrdenarPor thenby
- 7. dinámico, LINQ y Select()
- 8. Obtener un IEnumerable <T> de un IEnumerable <IEnumerable <T>>
- 9. Encuentra secuencia en IEnumerable <T> usando LINQ
- 10. Error de compilación dinámico + linq
- 11. problema con la función genérica LINQ OrdenarPor
- 12. OrdenarPor y distinto utilizando entidades LINQ-a-
- 13. Convertir/Convertir IEnumerable en IEnumerable <T>
- 14. OrdenarPor ThenBy en Fa #
- 15. IEnumerable <> to IList <>
- 16. Cómo convertir un IEnumerable <IEnumerable <T>> a un IEnumerable <T>
- 17. ¿LINQ funciona con IEnumerable?
- 18. Cómo puedo dividir un IEnumerable <String> en grupos de IEnumerable <string>
- 19. sintaxis de LINQ para OrdenarPor con Comparer encargo <T>
- 20. Dinámico donde condición en LINQ
- 21. ¿Desarrollar LINQ dinámico?
- 22. LINQ: ¿Cómo declarar IEnumerable [AnonymousType]?
- 23. LINQ a Entidades - se aplica varios métodos OrdenarPor no funcionan
- 24. Convertir LINQ OrdenarPor a inplace lista de ordenación
- 25. LINQ - seleccionando segundo elemento en IEnumerable
- 26. La agrupación de artículos idénticos consecutivos: IEnumerable <T> a IEnumerable <IEnumerable <T>>
- 27. Por qué IEnumerable <T> se define como IEnumerable <out T>, no IEnumerable <T>
- 28. OrdenarPor descendente en la expresión Lambda?
- 29. Fundir/Convertir IEnumerable <T> en IEnumerable <U>?
- 30. IEnumerable <CustomType> en PowerShell
Mejor pedazo de código que he visto :) Acabo de resolver un millón de problemas en mi proyecto :) – sajidnizami
Marc, ¿Tiene la extensión similar para la condición LIKE? – Prasad
@Prasad - 'LIKE' es un poco diferente, pero ¿qué back-end? Para LINQ-to-SQL, hay 'SqlMethods.Like': http://msdn.microsoft.com/en-us/library/system.data.linq.sqlclient.sqlmethods.like.aspx; ¿Puedes agregar más información de lo que estás buscando? –