2012-10-05 73 views
20

Hay dos formatos para cualquier expresión LINQ dada con un comparador de ordenación personalizada:sintaxis de LINQ para OrdenarPor con Comparer encargo <T>

Formato 1

var query = 
    source 
    .Select(x => new { x.someProperty, x.otherProperty }) 
    .OrderBy(x => x, new myComparer()); 

Formato 2

var query = 
    from x in source 
    orderby x // comparer expression goes here? 
    select new { x.someProperty, x.otherProperty }; 

pregunta :
¿Cuál es la sintaxis de la expresión de orden en la segunda forma t?

No es la pregunta: ¿
Cómo utilizar un comparador personalizado como se muestra en el primer formato.

crédito de bonificación:
¿Hay nombres reales, formales de los dos formatos de Linq mencionados anteriormente?

Respuesta

19

¿Cuál es la sintaxis de la orden por la expresión en el segundo formato?

No existe. Del orderby clause documentation:

También puede especificar un comparador personalizado. Sin embargo, solo está disponible al usar sintaxis basada en método.


Cómo utilizar un comparador personalizado en el primer formato.

Lo escribió correctamente. Puede pasar el IComparer<T> mientras escribe.


¿Hay nombres reales, formales de los dos formatos de Linq mencionados anteriormente?

Formato 1 se llama "Método basado en sintaxis" (from previous link), y formato 2 es "expresión de consulta de sintaxis" (de here).

+1

¡Enlaces de calidad! Aunque la afirmación sobre la sintaxis order-by en la sintaxis basada en el método realmente no se suponía que formara parte de la respuesta. :) –

+1

@SteveKonves Acabo de incluirlo de todos modos. Usted puede ignorar fácilmente;) –

2

Cómo usar un comparador personalizado como se muestra en el primer formato.

No puede usar un comparador personalizado en ese formato.

¿Existen nombres reales y formales para los dos formatos Linq enumerados anteriormente?

Formato 1 es sintaxis del método, es el formato 2 "sintaxis de la consulta",

2

Pregunta:

eso no es posible en la sintaxis de la consulta, porque no existen sobrecargas.

No es la pregunta: ¿

Puede utilizar un comparador con los tipos anónimos sólo si se utiliza la reflexión para comparar los objetos, es mejor utilizar una aplicación escrito para comparar.

Si no desea crear una aplicación escrita a máquina se puede utilizar un Tuple: crédito

var query = 
    source 
    .Select(x => new Tuple<string, int>(x.someProperty, x.otherProperty)) 
    .OrderBy(x => x, new MyComparer()); 

public class MyComparer : IComparer<Tuple<string, int>> 
{ 
    public int Compare(Tuple<string, int> x, Tuple<string, int> y) 
    { 
    return x.Item1.CompareTo(y.Item1); 
    } 
} 

Bono: sintaxis Método

  • sintaxis de consulta o Comprensión Sintaxis
  • o Método de extensión Sintaxis
2

Esto no necesariamente responde a la pregunta original, pero de alguna manera amplía algunas de las posibilidades delineadas. Estoy publicando esto en caso de que otros encuentren el problema similar. La solución publicada aquí describe un orden genérico por opción que puede ser útil en otros casos. En este ejemplo, quería ordenar una lista de archivos por diferentes propiedades.

/// <summary> 
/// Used to create custom comparers on the fly 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public class GenericCompare<T> : IComparer<T> 
{ 
    // Function use to perform the compare 
    private Func<T, T, int> ComparerFunction { set; get; } 

    // Constructor 
    public GenericCompare(Func<T, T, int> comparerFunction) 
    { 
     ComparerFunction = comparerFunction; 
    } 

    // Execute the compare 
    public int Compare(T x, T y) 
    { 

     if (x == null || y == null) 
     { 
      // These 3 are bell and whistles to handle cases where one of the two is null, to sort to top or bottom respectivly 
      if (y == null && x == null) { return 0; } 
      if (y == null) { return 1; } 
      if (x == null) { return -1; } 
     } 

     try 
     { 
      // Do the actual compare 
      return ComparerFunction(x, y); 
     } 
     catch (Exception ex) 
     { 
      // But muffle any errors 
      System.Diagnostics.Debug.WriteLine(ex); 
     } 

     // Oh crud, we shouldn't be here, but just in case we got an exception. 
     return 0; 
    } 
} 

Luego, en la puesta en práctica ...

 GenericCompare<FileInfo> DefaultComparer; 

     if (SortOrder == SORT_FOLDER_FILE) 
     { 
      DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) => 
      { 
       return fr1.FullName.ToLower().CompareTo(fr2.FullName.ToLower()); 
      }); 
     } 
     else if (SortOrder == SORT_SIZE_ASC) 
     { 
      DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) => 
      { 
       return fr1.Length.CompareTo(fr2.Length); 
      }); 
     } 
     else if (SortOrder == SORT_SIZE_DESC) 
     { 
      DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) => 
      { 
       return fr2.Length.CompareTo(fr1.Length); 
      }); 
     } 
     else 
     { 
      DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) => 
      { 
       return fr1.Name.ToLower().CompareTo(fr2.Name.ToLower()); 
      }); 
     } 

     var ordered_results = (new DirectoryInfo(@"C:\Temp")) 
       .GetFiles() 
       .OrderBy(fi => fi, DefaultComparer); 

La gran ventaja es que entonces no es necesario crear una nueva clase para cada orden por caso, sólo se puede cablear una nueva lambda. Obviamente, esto se puede extender de muchas maneras, así que con suerte ayudará a alguien, en algún lugar, alguna vez.

Cuestiones relacionadas