2012-09-12 35 views
0

与下面的代码LINQ查询,我没有任何问题进行排序FirstNameLastName 但我希望能够排序NameCode了。有没有一种解决方案来排序属性,这个属性是一个“复杂的对象”,而不是一个原始的?对财产动态排序依据和复杂的对象

感谢,

我的对象:

public class Person 
{ 
    public Language Language { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

public class Language 
{ 
    public string Name { get; set; } 
    public string Code { get; set; } 
} 

我有这样的一段代码进行排序:

var type = typeof(T); 
var property = type.GetProperty("OrderBy"); 
var parameter = Expression.Parameter(type, "p"); 
var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
var orderByExp = Expression.Lambda(propertyAccess, parameter); 
MethodCallExpression resultExp = 
    Expression.Call(typeof(Queryable), 
    "OrderBy", 
    new Type[] { type, property.PropertyType }, 
    source.Expression, 
    Expression.Quote(orderByExp)); 
return source.Provider.CreateQuery<T>(resultExp); 
+1

代码中没有子类。名称和代码是您的Person类的属性的属性。 –

+0

@MaurícioLinhares让我重述一下......并不是所有的时间都是“语言”对象,但可以是另一种类型。 –

+0

@ Kris-I:请编辑问题的标题,然后 - 我阅读它也寻找子类。 –

回答

2

有没有排序的属性及该物业的解决方案是一个“复杂的对象”而不是一个原始的?

当然 - 你必须从根本上建立表达式树相当于一个:

data.OrderBy(p => p.Language.Name) 

这两种基本属性访问表达式,在其中一人的“源”是“结果”的另一个。所以你需要把你的属性字符串(例如“Language.Name”),分成几个部分,然后迭代各个位,保持当前表达式作为目标。例如:

Expression parameter = Expression.Parameter(type, "p"); 
Expression target = parameter; 
foreach (string property in propertyParts) 
{ 
    target = Expression.Property(target, property); 
} 
var orderByExp = Expression.Lambda(target, parameter); 
+0

你可以用一个简单的折叠替换循环:'target = propertyParts.Aggregate(target,Expression.Property);'。 此外,我想你忘了声明和分配'参数'。 –

+1

@ThomSmith:修正了参数的声明,但是我个人会发现'foreach'循环比'Aggregate'调用更容易理解。在所有的LINQ操作符中,我发现'Aggregate'是最不容易使用的一个。我理解这些原则 - 我总是发现,当使用这些原则时,我必须更加努力地思考。很明显,如果你来自功能性背景,当然可能有帮助... –

+0

YMMV。 'Aggregate'有时会让我感到不安,可能是因为微软决定任意重命名所有LINQ的标准函数操作符,并且二进制'fold'和一元'reduce'被绑在一起。 –