私のプロジェクトには、文字列でIEnumerable
を並べ替えて並べ替えることができるような拡張があり、より動的に並べ替えることができます。だから、並べ替えのための式ツリーを動的に構築
、私はこれらのモデルがある場合:私のオブジェクトはICollection<ChildModel> MyChildren
のように、私はハード私の並べ替えをコーディングすることができ、ICollection
性質を持っている場合は、しかし、
myList.OrderByField("RecordName ");
myList.OrderByField("MyChild.SavedDate");
:
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;}
}
を、私は2つの方法で並べ替えることができますこのように:
myList
.OrderBy(m => m.MyChildren
.OrderByDescending(c => c.SavedDate).FirstOrDefault().SavedDate);
私が欲しいものを得る。
私の質問はどのように私はこれと同じ結果を得ることができるように私の拡張メソッドを更新することができ、である:ここで
myList.OrderByField("MyChildren.SavedDate");
を私の現在の延長である:
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;
}
}
私が考えていましたprop
のタイプをチェックし、if... else
ステートメントを実行していますが、わかりません。
たぶん、このような何か:
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、あなたのようなので、ハードコーディングされたネストされた順序付けを簡素化することができます:ここでは
は、式ツリーを通じてMax
をコールする方法の例です。 (c => c.SavedDate)); '。あなたのプログラムが '' MyChildren.SavedDate "'を見たとき、MyChildrenによって昇順に並べ替えることを知っていますが、SavedDateで降順にする方法はどうですか? – StriplingWarriorマックスは子レコードのために働くでしょう。私の文字列では、実際には 'MyChildren.SavedDate asc'や' MyChildren.SavedDate desc'を使い、それを反転させます。 '.SavedDate'は最近のものを前提としています。 ;) –