2013-07-15 3 views
10

Я использую эту функцию динамического linq orderby, которую я получил от here.Динамический linq-порядок по вложенному свойству с нулевыми свойствами

Это прекрасно работает с вложенными свойствами, так что я мог бы сделать это:

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

Проблема заключается в том, что если SomeProperty равна нулю, то выполнение OrderBy на NestedProperty бросает позорную «ссылка на объект не указывает на экземпляр объект".

Я думаю, что мне нужно настроить следующие строки для обработки исключения:

expr = Expression.Property(expr, pi); 

// Or 

LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);  

Я думал о создании тела заявление, где я мог бы в худшем случае использовать в попытке поймать, но это Ждут» t, так как вы не можете иметь тела оператора в порядке выполнения операторов linq: «ЯМР-выражение с телом оператора не может быть преобразовано в дерево выражений»

Я потерян здесь, любые предложения о том, как я могу это сделать ?

Кстати, это для Linq для объектов, а не для базы данных.

+0

Я предполагаю, что эта строка 'выр = Expression.Property (выражение, пи),' 'наборы expr' к нулю и далее код не обрабатывает его. Самый простой способ исправить это: 'expr = Expression.Property (expr, pi) ?? по умолчанию (Т); '. Однако в этом случае вам нужно будет проверить, согласны ли вы с применяемым порядком. – Tommi

+0

Это хороший момент, на самом деле это сделало бы работу сортировки неправильной, в идеале нули должны быть «сгруппированы» вместе. –

+0

Посмотрите, поможет ли это вам каким-либо образом http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet?lq=1 – Ehsan

ответ

5
static void Main(string[] args) 
{ 
    var data = new List<MyType>() { 
     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; 
    } 
} 
+0

Отлично, этот выглядит проще, чем ответ Марка Гравеля, что заставляет меня задуматься. Тем не менее, все мои тесты, похоже, работают очень хорошо, и вы сделали меня счастливыми людьми. –

+0

Очень умный. Хороший трюк с рекурсией. Microsoft должна предоставить это как метод расширения в будущих рамках. – arviman

+0

Что делать, если вместо SomeProperty у вас есть список ? Как можно было бы изменить вышеуказанный код, чтобы справиться с этим делом? – demonicdaron

3

Как насчет дженериков:

Helper Метод:

public static Expression<Func<TEntity, TResult>> GetExpression<TEntity, TResult>(string prop) 
     { 
      var param = Expression.Parameter(typeof(TEntity), "p"); 
      var parts = prop.Split('.'); 

      Expression parent = parts.Aggregate<string, Expression>(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<Func<TEntity, TResult>>(tryExpression, param); 
     } 

Пример иерархии:

public class A 
    { 
     public A(B b) 
     { 
      B = b; 
     } 

     public B B { get; set; } 
    } 

    public class B 
    { 
     public B(C c) 
     { 
      C = c; 
     } 

     public C C { get; set; } 
    } 

    public class C 
    { 
     public C(int id) 
     { 
      this.Id = id; 
     } 

     public int Id { get; set; } 
    } 

Пример:

var list = new List<B> 
      { 
       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<B, Object>("AProp.CProp.Id")); 

Выход:

3 
2 
1 
Null 
Null 
+1

Ты гений, большое спасибо! – Alexander

Смежные вопросы