2012-10-05 15 views
20

Ci sono due formati per qualsiasi espressione di Linq con un ordinamento personalizzato di confronto:sintassi LINQ per OrderBy con Comparer personalizzato <T>

Format 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 }; 

domanda :
Qual è la sintassi per l'espressione order-by nella seconda forma t?

Non la domanda:
Come utilizzare un operatore di confronto personalizzato come mostrato in primo formato.

credito Bonus:
ci sono reali, nomi formali per i due formati Linq sopra elencati?

risposta

19

Qual è la sintassi per l'ordine-by espressione nel secondo formato?

Non esiste. Da orderby clause documentation:

È inoltre possibile specificare un comparatore personalizzato. Tuttavia, è disponibile solo utilizzando la sintassi basata sui metodi.


Come utilizzare un operatore di confronto personalizzato nel primo formato.

L'hai scritto correttamente. Puoi passare lo IComparer<T> come hai scritto.


Vi sono reali, nomi formali per i due formati Linq sopra elencati?

Format 1 si chiama "Metodo-Based di sintassi" (from previous link), e il formato 2 è "Query Expression sintassi" (da here).

+1

Collegamenti di qualità linq! Sebbene l'affermazione sulla sintassi order-by nella sintassi basata sul metodo non avrebbe dovuto far parte della risposta. :) –

+1

@SteveKonves L'ho appena incluso comunque. Puoi facilmente ignorare;) –

2

Come utilizzare un comparatore personalizzato come mostrato nel primo formato.

Non è possibile utilizzare un comparatore personalizzato in tale formato.

Esistono nomi effettivi e formali per i due formati Linq sopra elencati?

Format 1 è la sintassi Metodo, Formato 2 è "query di sintassi",

2

Domanda:

quello non è possibile nella sintassi di query, perché non ci sono sovraccarichi.

Non la domanda:

È possibile utilizzare un operatore di confronto con i tipi anonimi solo se si utilizza la reflection per confrontare gli oggetti, è meglio usare un'implementazione digitato per il confronto.

Se non si desidera creare un'implementazione digitato È possibile utilizzare un Tuple: credito

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); 
    } 
} 

Bonus:

  • sintassi di query o comprensione Sintassi
  • sintassi del metodo o Metodo di estensione Sintassi
2

Questo non risponde necessariamente alla domanda originale, ma estende in parte alcune delle possibilità delineate. Sto postando questo nel caso in cui altri si imbattano nel problema simile. La soluzione pubblicata qui delinea un ordine generico per opzione che potrebbe essere utile in altri casi. In questo esempio, ho voluto ordinare un elenco di file con proprietà diverse.

/// <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; 
    } 
} 

Poi nella realizzazione ...

 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); 

Il grande vantaggio è che allora non c'è bisogno di creare una nuova classe per ogni ordine per caso, si può semplicemente collegare un nuovo lambda. Ovviamente questo può essere esteso in tutti i modi, quindi speriamo che aiuti qualcuno, da qualche parte, a volte.