2016-07-01 7 views
0

Ich habe ein bisschen eine Herausforderung. Ich muss eine Liste von Objekten sortieren, und ich muss es aus einer Zeichenfolge sortieren, die den Pfad zu der Eigenschaft in jeder Unterklasse darstellt. Ich brauche die List.Sort() und nicht OrderBy().List.Sort von Eigenschaftsname - einschließlich Unterklassen

Lest machen ein einfaches Beispiel. Ich habe eine Liste von Personen, die von zwei Unterklassen für die Identifizierung vertreten und nennen

public class NameParts 
{ 
    public String FirstName { get; set; } 
    public String LastName { get; set; } 
} 

public class Identification 
{ 
    public String NiNumber { get; set; } 
    public NameParts Name { get; set; } 
} 

public class Person 
{ 
    public String Email { get; set; } 
    public String Phone { get; set; } 
    public Int16 Age { get; set; } 

    public Identification Id { get; set; } 
} 

Jetzt muss ich die Liste nach Alter sortiert werden. Sehr einfache

public static void SortByAge(List<Person> listToSort) 
{ 
    listToSort.Sort((x, y) => x.Age.CompareTo(y.Age)); 
} 

Und auch von NiNumber und Vorname ist es ziemlich einfach, auf diese Weise

public static void SortByNiNumber(List<Person> listToSort) 
{ 
     listToSort.Sort((x, y) => x.Id.NiNumber.CompareTo(y.Id.NiNumber)); 
} 

public static void SortByFirstName(List<Person> listToSort) 
{ 
     listToSort.Sort((x, y) => x.Id.Name.FirstName.CompareTo(y.Id.Name.FirstName)); 
} 

Jetzt kommt der schwierige Teil. Ich muss alle oben genannten Arten durchführen, die eine Schnur geben, die den Pfad zur Eigenschaft darstellt, um zu sortieren. Like „Id.Name.FirstName“

Also muss ich

public static void SortByAny(List<Person> listToSort, String sortBy) 
{ 
    //?????? 
} 

, die mit

List<Person> theList = new List<Person>(); 
SortByAny(theList, "Age"); 
SortByAny(theList, "Id.NiNumber"); 
SortByAny(theList, "Id.Name.FirstName"); 

genannt werden kann, ich weiß ich für diese Reflexion verwenden müssen, und ich habe es geschafft, tun Sie es, aber ich kann nicht weiter kommen als die Eigenschaften in der Personenklasse selbst, also muss ich wahrscheinlich etwas anderes tun, und das ist, wo ich feststecke.

Hat jemand einige brillante Ideen, wie man das löst?

Dank

+0

Sie könnten wahrscheinlich einen Teil dieser Lösung verwenden: http://stackoverflow.com/questions/4473928/c-sharp-dynamic-string-property-path –

+0

Können Sie erklären, warum Sie das brauchen? Vielleicht gibt es eine andere Lösung für Ihr Problem –

+0

Ich brauche es, weil ich eine einzige Sortiermethode über die Implementierung der Sortiermethode i jede von 10-100 Klassen mit Switches für alle Sortieroptionen bevorzugen würde. natürlich würde das gut funktionieren, aber gibt mir eine Menge Code zu pflegen – Beaker

Antwort

0

Sie können den Ansatz @ E.Mourits verknüpft ändern: C# dynamic. String property path. Ich habe ein bisschen Fehlerprüfung, bei Fehler müssen Sie die InnerException der InvalidOperationException die Sort Methode werfen können zu überprüfen.

static void SortByAny<T>(List<T> list, string path) 
{ 
    list.Sort((x, y) => ReflectOnPath(x, path).CompareTo(ReflectOnPath(y, path))); 
} 

static IComparable ReflectOnPath(object o, string path) 
{ 
    object value = o; 
    var pathComponents = path.Split('.'); 
    foreach (var component in pathComponents) 
    { 
     if (value == null) 
     { 
      throw new NullReferenceException($"Path '{path}' can not be resolved at: {component}."); 
     } 
     var prop = value.GetType().GetProperty(component); 
     if (prop == null) 
     { 
      throw new ArgumentException($"Path '{path}' can not be resolved at: {component}.", nameof(path)); 
     } 
     value = prop.GetValue(value, null); 
    } 
    if (!(value is IComparable)) 
    { 
     throw new ArgumentException($"Value at path '{path}' does not implement ICompareable.", nameof(path)); 
    } 
    return (IComparable)value; 
} 

Wenn einige der Werte, die Sie IComparable Sie vergleichen wollen nicht implementieren mehr Details hinzufügen, wie Sie sie in diesem Fall vergleichen möchten.

+0

Wow, das hat funktioniert. :) – Beaker

+0

Nur Problem mit diesen Lösungen ist Performance. Glauben Sie nicht, dass es viel zu optimieren gibt. – Beaker

0

Da durch Reflexionseigenschaften bekommen ist ziemlich schwer zu tun, nur diesen Code verwenden und ändern:

public static void SortByAny(List<Person> listToSort, String sortBy) 
{ 
    if (sortBy == "Email") 
     listToSort.Sort((x, y) => x.Email.CompareTo(y.Email)); 
    else if (sortBy == "Phone") 
     listToSort.Sort((x, y) => x.Phone.CompareTo(y.Phone)); 
    else if (sortBy == "Age") 
     listToSort.Sort((x, y) => x.Age.CompareTo(y.Age)); 
    else if (sortBy == "Id.NiNumber") 
     listToSort.Sort((x, y) => x.Id.NiNumber.CompareTo(y.Id.NiNumber)); 
    else if (sortBy == "Id.Name.FirstName") 
     listToSort.Sort((x, y) => x.Id.Name.FirstName.CompareTo(y.Id.Name.FirstName)); 
    else if (sortBy == "Id.Name.LastName") 
     listToSort.Sort((x, y) => x.Id.Name.LastName.CompareTo(y.Id.Name.LastName)); 
} 
+0

Danke für den Vorschlag Das war mehr oder weniger, was ich kam, aber das Problem ist mit tiefer Bohren .. – Beaker

0

Haben Sie wirklich brauchen Reflexion an Ort und Stelle setzen? Wenn Sie die Liste nach einer bestimmten und bestimmten Anzahl von "Pfaden" sortieren müssen, würde ich vorschlagen, dass Sie sie auf eine feste Art und Weise implementieren und geradeaus mit der Sortierung fortfahren. vielleicht könnte ein Schalter helfen?

switch(sortByString){ 
    case: "Id.NiNumber": 
    SortByNiNumber(List<Person> listToSort); 
    break; 
    ... 
} 

Wenn Sie nicht zu viele Optionen haben, wäre es schneller. Und vielleicht können Sie den Schalter durch ein Wörterbuch von Suchpfaden und Delegaten oder Aktionen ersetzen.

+0

Ich mache es so jetzt. Aber das muss an jeder Klasse funktionieren und nicht nur an Person, und ich brauche es, um nicht alle Sortierausdrücke für alle Klassen schreiben zu müssen ... – Beaker

+0

Mmh ... Schätze, du solltest ein bisschen mehr Hintergrund geben. Normalerweise, wenn ich etwas so "universal" machen muss, ändert sich die Antwort nur, indem ich den Standpunkt ändere und darüber nachdenke. –

Verwandte Themen