Ich habe nicht den ganzen Thread durchgesehen, also kann es schon hier sein, aber:
public static class FluentOrderingExtensions
public class FluentOrderer<T> : IEnumerable<T>
{
internal List<Comparison<T>> Comparers = new List<Comparison<T>>();
internal IEnumerable<T> Source;
public FluentOrderer(IEnumerable<T> source)
{
Source = source;
}
#region Implementation of IEnumerable
public IEnumerator<T> GetEnumerator()
{
var workingArray = Source.ToArray();
Array.Sort(workingArray, IterativeComparison);
foreach(var element in workingArray) yield return element;
}
private int IterativeComparison(T a, T b)
{
foreach (var comparer in Comparers)
{
var result = comparer(a,b);
if(result != 0) return result;
}
return 0;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
public static FluentOrderer<T> OrderFluentlyBy<T,TResult>(this IEnumerable<T> source, Func<T,TResult> predicate)
where TResult : IComparable<TResult>
{
var result = new FluentOrderer<T>(source);
result.Comparers.Add((a,b)=>predicate(a).CompareTo(predicate(b)));
return result;
}
public static FluentOrderer<T> OrderFluentlyByDescending<T,TResult>(this IEnumerable<T> source, Func<T,TResult> predicate)
where TResult : IComparable<TResult>
{
var result = new FluentOrderer<T>(source);
result.Comparers.Add((a,b)=>predicate(a).CompareTo(predicate(b)) * -1);
return result;
}
public static FluentOrderer<T> ThenBy<T, TResult>(this FluentOrderer<T> source, Func<T, TResult> predicate)
where TResult : IComparable<TResult>
{
source.Comparers.Add((a, b) => predicate(a).CompareTo(predicate(b)));
return source;
}
public static FluentOrderer<T> ThenByDescending<T, TResult>(this FluentOrderer<T> source, Func<T, TResult> predicate)
where TResult : IComparable<TResult>
{
source.Comparers.Add((a, b) => predicate(a).CompareTo(predicate(b)) * -1);
return source;
}
}
Verwendung:
var myFluentlyOrderedList = GetABunchOfComplexObjects()
.OrderFluentlyBy(x=>x.PropertyA)
.ThenByDescending(x=>x.PropertyB)
.ThenBy(x=>x.SomeMethod())
.ThenBy(x=>SomeOtherMethodAppliedTo(x))
.ToList();
... natürlich vorausgesetzt, dass alle Prädikate Typen zurückgeben, die IComparable zu sich selbst sind. Es würde besser mit einer stabilen Sortierung wie ein MergeSort anstelle von .NET eingebauten QuickSort arbeiten, aber es bietet Ihnen mit lesbaren Multi-Feld-Bestellung Fähigkeit ähnlich wie SQL (so nah wie eine Methode Kette bekommen kann, sowieso). Sie können dies erweitern, um Mitglieder unterzubringen, die nicht IComparable sind, indem Sie Überladungen definieren, die ein Vergleichslambda nehmen, anstatt es basierend auf einem Prädikat zu erstellen.
EDIT: Eine kleine Erläuterung, da der Kommentator einige Anregungen erhalten hat: Diese Methodenreihe verbessert die grundlegende OrderBy()-Funktionalität, indem sie es Ihnen ermöglicht, nach mehreren Feldern in absteigender Reihenfolge zu sortieren. Ein praktisches Beispiel wäre das Sortieren einer Liste von Rechnungen nach Kunde, dann nach Rechnungsnummer (oder Rechnungsdatum). Andere Methoden, um die Daten in dieser Reihenfolge zu erhalten, würden entweder nicht funktionieren (OrderBy() verwendet eine instabile Sortierung, so dass sie nicht verkettet werden kann) oder wären ineffizient und würden nicht so aussehen, als ob sie das tun, was Sie zu tun versuchen.