具有null属性的嵌套属性上的动态linq顺序

我正在使用这个动态的linq orderby函数,我从这里得到了 。

这适用于嵌套属性,所以我可以这样做:

var result = data.OrderBy("SomeProperty.NestedProperty"); 

问题是,如果SomeProperty为null,则在NestedProperty上执行OrderBy会抛出臭名昭着的“对象引用未设置为对象的实例”。

我的猜测是我需要自定义以下行来处理exception:

 expr = Expression.Property(expr, pi); // Or LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg); 

我考虑创建一个语句体,在最坏的情况下,我可以使用try catch,但这不起作用,因为你不能在orderby linq语句中有语句体:“带有语句体的lambda表达式无法转换为表达树“

我迷失在这里,有关如何实现这一目标的任何建议?

顺便说一句,这是针对Linq to Objects,而不是数据库相关的。

 static void Main(string[] args) { var data = new List() { new MyType() { SomeProperty = new Inner() { NestedProperty = "2" }}, new MyType() { SomeProperty = new Inner() { NestedProperty = "1" }}, new MyType() { SomeProperty = new Inner() { NestedProperty = "3" }}, new MyType(), }.AsQueryable(); var sorted = data.OrderBy(x => GetPropertyValue(x, "SomeProperty.NestedProperty")); foreach (var myType in sorted) { try { Console.WriteLine(myType.SomeProperty.NestedProperty); } catch (Exception e) { Console.WriteLine("Null"); } } } public static object GetPropertyValue(object obj, string propertyName) { try { foreach (var prop in propertyName.Split('.').Select(s => obj.GetType().GetProperty(s))) { obj = prop.GetValue(obj, null); } return obj; } catch (NullReferenceException) { return null; } } 

仿制药怎么样:

帮手方法:

 public static Expression> GetExpression(string prop) { var param = Expression.Parameter(typeof(TEntity), "p"); var parts = prop.Split('.'); Expression parent = parts.Aggregate(param, Expression.Property); Expression conversion = Expression.Convert(parent, typeof (object)); var tryExpression = Expression.TryCatch(Expression.Block(typeof(object), conversion), Expression.Catch(typeof(object), Expression.Constant(null))); return Expression.Lambda>(tryExpression, param); } 

示例层次结构:

 public class A { public A(B b) { B = b; } public BB { get; set; } } public class B { public B(C c) { C = c; } public CC { get; set; } } public class C { public C(int id) { this.Id = id; } public int Id { get; set; } } 

例:

 var list = new List { new B(new A(new C(1))), new B(new A(new C(2))), new B(new A(new C(3))), new B(new A(null)), new B(null) }.AsQueryable(); var ordered = list.OrderByDescending(GetExpression("AProp.CProp.Id")); 

输出:

 3 2 1 Null Null