für die Sortierung ich eine Erweiterung in meinem Projekt, das ich Lassen Sie sich ein IEnumerable
mit einer Schnur sortieren, so dass das Sortieren dynamischer erfolgen.Dynamisch einen Ausdruck Baum bauen
Also, wenn ich diese Modelle haben:
public MyModel
{
public int Id {get; set;}
public string RecordName {get; set;}
public ChildModel MyChild {get; set;}
}
public ChildModel
{
public int ChildModelId {get; set;}
public DateTime SavedDate {get; set;}
}
kann ich zwei Arten sortieren:
myList.OrderByField("RecordName ");
myList.OrderByField("MyChild.SavedDate");
Wenn jedoch meine Aufgabe, eine ICollection
Eigenschaft hat, wie ICollection<ChildModel> MyChildren
ich meine Art hart codieren wie folgt:
myList
.OrderBy(m => m.MyChildren
.OrderByDescending(c => c.SavedDate).FirstOrDefault().SavedDate);
Und bekommen, was ich will.
Meine Frage ist, wie kann ich meine Erweiterungsmethode aktualisieren, um die gleichen Ergebnisse mit diesem zu ermöglichen, zu erhalten:
myList.OrderByField("MyChildren.SavedDate");
Hier ist meine aktuelle Erweiterung:
public static class MkpExtensions
{
public static IEnumerable<T> OrderByField<T>(this IEnumerable<T> list, string sortExpression)
{
sortExpression += "";
string[] parts = sortExpression.Split(' ');
bool descending = false;
string fullProperty = "";
if (parts.Length > 0 && parts[0] != "")
{
fullProperty = parts[0];
if (parts.Length > 1)
{
descending = parts[1].ToLower().Contains("esc");
}
ParameterExpression inputParameter = Expression.Parameter(typeof(T), "p");
Expression propertyGetter = inputParameter;
foreach (string propertyPart in fullProperty.Split('.'))
{
PropertyInfo prop = propertyGetter.Type.GetProperty(propertyPart);
if (prop == null)
throw new Exception("No property '" + fullProperty + "' in + " + propertyGetter.Type.Name + "'");
propertyGetter = Expression.Property(propertyGetter, prop);
}
Expression conversion = Expression.Convert(propertyGetter, typeof(object));
var getter = Expression.Lambda<Func<T, object>>(conversion, inputParameter).Compile();
if (descending)
return list.OrderByDescending(getter);
else
return list.OrderBy(getter);
}
return list;
}
}
Ich dachte die Art der prop
zu kontrollieren und dabei eine if... else
Aussage, aber ich bin mir nicht sicher.
Vielleicht so etwas wie:
foreach (string propertyPart in fullProperty.Split('.'))
{
var checkIfCollection = propertyGetter.Type.GetInterfaces()//(typeof (ICollection<>).FullName);
.Any(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(ICollection<>) || x.GetGenericTypeDefinition() == typeof(IEnumerable<>)));
if (checkIfCollection)
{
// Can I get this to do something like
// myList.OrderBy(m => m.MyChildren.Max(c => c.SavedDate));
// So far, I can get the propertyGetter type, and the type of the elements:
var pgType = propertyGetter.Type;
var childType = pgType.GetGenericArguments().Single();
// Now I want to build the expression tree to get the max
Expression left =
Expression.Call(propertyGetter, pgType.GetMethod("Max", System.Type.EmptyTypes));
// But pgType.GetMethod isn't working
}
else
{
PropertyInfo prop = propertyGetter.Type.GetProperty(propertyPart);
if (prop == null)
throw new Exception("No property '" + fullProperty + "' in + " + propertyGetter.Type.Name + "'");
propertyGetter = Expression.Property(propertyGetter, prop);
}
}
FYI, können Sie die hartcodierte verschachtelte Anordnung vereinfachen etwa so: 'myList.OrderBy (m => m.MyChildren.Max (c => c.SavedDate)); '. Apropos, wenn Ihr Programm sieht '„MyChildren.SavedDate“', wie ist es denn wissen von MyChildren zu sortieren aufsteigend, aber absteigend nach SavedDate? – StriplingWarrior
Max wird für die untergeordneten Datensätze funktionieren. In meinem String verwende ich 'MyChildren.SavedDate asc' tatsächlich oder' MyChildren.SavedDate desc' und Flip accordingling. '.SavedDate' nimmt zuletzt ... an. ;) –