2012-03-30 27 views
5

tengo código como el siguiente:Entidad marco genérico

switch(sort.Column) 
{ 
    case "code": 
    model = (sort.Direction == SortDirection.Ascending) 
      ? model.OrderBy(x => x.code) 
      : model.OrderByDescending(x => x.code); 
    break; 
    case "name": 
    model = (sort.Direction == SortDirection.Ascending) 
      ? model.OrderBy(x => x.name) 
      : model.OrderByDescending(x => x.name); 
    break; 
.............. 
} 

tengo unos 10-15 campos (como 'código' y 'nombre') y yo no quiero copiar y pegar un código similar con una sola diferencia - nombre del campo.

¿Hay algún método para generalizar la consulta de alguna manera?

+0

¿Sabes qué es gracioso? Tenemos este código exacto en funcionamiento, en una clase SortHelper que se pega unas 200 veces: |. ¡Interesado en ver qué pasa con esto! +1 – mattytommo

Respuesta

7

Puede utilizar la reflexión (esto supone code y name son propiedades; si son variables públicas, tendrá que modificar en consecuencia):

model = (sort.Direction == SortDirection.Ascending) 
    ? model.OrderBy(x => x.GetType() 
     .GetProperty(sort.Column).GetValue(x, null)) : 
    : model.OrderByDescending(x => x.GetType() 
     .GetProperty(sort.Column).GetValue(x, null)); 

Como Dunc señala en los comentarios a continuación, este enfoque obliga a la reflexión en cada paso de la enumeración, y la reflexión es costosa a medida que avanzan las operaciones. Si su colección es homogénea, puede lograr un mejor rendimiento retirando la reflexión de la enumeración. Si su model contiene sólo elementos de tipo Foo, puede hacer lo siguiente en su lugar:

var prop = typeof(Foo).GetProperty(sort.Column); 

model = (sort.Direction == SortDirection.Ascending) 
    ? model.OrderBy(x => prop.GetValue(x, null)) : 
    : model.OrderByDescending(x => prop.GetValue(x, null)); 

Por favor, no es que esto arrojará un TargetException si su colección no es homogénea.

+0

Sugerencia de rendimiento agradable y pequeña: intente mover x.GetType(). GetProperty (sort.Column) fuera de la expresión LINQ para evitar reflexiones repetidas – Dunc

+0

Buena sugerencia, Dunc, actualizaré mi respuesta en consecuencia. –

3

Esto lo haría comenzar, pero también podría usar el reflejo para obtener el nombre de la propiedad a través de la columna, si la propiedad y la columna coinciden exactamente.

// inline function 
Func<Func<Model, TResult>, Model> Order = criteria => 
{ 
    return (sort.Direction == SortDirection.Ascending) 
      ? model.OrderBy(criteria) 
      : model.OrderByDescending(criteria); 
} 

... code down to switch ... 

Esto acortaría su caso a nombre de:

model = Order(x => x.name); 

Pero con la reflexión, podría hacerlo sin el interruptor, pero estoy un poco débil en la reflexión, así que voy a dejarlo a otra persona si así lo desean.

1

Como dice 'No such IP', hay patrones para esto - despachador de comandos/método de fábrica/etc. Esas son elecciones válidas. Pero a veces esto puede ocultar la complejidad. Mi sugerencia es mirar usando dynamic linq. Aquí hay un enlace para que comience: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

También puede hacer las suyas propias si lo desea, ya que no es demasiado complicado. Cree métodos de extensión propios que le permitan pasar parámetros (es decir, ordenar dirección, ordenar columna) sobre su pedido y, dentro de ese método de extensión, crear su propia orden por declaración usando el espacio de nombres system.linq.expressions. Este es un ejemplo de eso también: http://ronniediaz.com/2011/05/24/orderby-string-in-linq-c-net-dynamic-sorting-of-anonymous-types/

+0

Buena solución, parece una fuente desensamblada de C# de consultas LINQ. –