Создать выражение из строки (нулевая ссылка) - PullRequest
1 голос
/ 01 февраля 2012

Вот проблема:

Мы используем объект таблицы, чтобы позволить пользователям выполнять некоторые функции, такие как поиск, сортировка, разбиение на страницы и т. Д. Эти таблицы отлично работают.Но есть проблема с одной из функций: Сортировка (= OrderBy).

Фактически, чтобы разрешить сортировку, мы устанавливаем в каждом столбце строку, которая представляет выражение: например, если выражениебудет Person => Person.Id, тогда строка будет Id;если выражение Person => Person.Address.Street, строка Address.Street.

В первом случае (Person => Person.Id) он прекрасно работает, поскольку не является подчиненным объектом.Но во втором случае (Person => Person.Address.Street) это не так, поскольку объект Address может быть нулевым.

Чтобы разрешить выполнение Orderby из строки, которую я нашел в другомопубликуйте следующие методы:

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "OrderBy");
}

public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "OrderByDescending");
}

public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "ThenBy");
}

public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "ThenByDescending");
}

private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
    string[] props = property.Split('.');
    Type type = typeof(T);
    ParameterExpression arg = Expression.Parameter(type, "x");
    Expression expr = arg;
    foreach (string prop in props)
    {
        // use reflection (not ComponentModel) to mirror LINQ 
        PropertyInfo pi = type.GetProperty(prop);
        expr = Expression.Property(expr, pi);
        type = pi.PropertyType;
    }
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
    object result = typeof(Queryable).GetMethods().Single(
    method => method.Name == methodName
        && method.IsGenericMethodDefinition
        && method.GetGenericArguments().Length == 2
        && method.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T), type)
            .Invoke(null, new object[] { source, lambda });
    return (IOrderedQueryable<T>)result;
}

У кого-нибудь из вас есть идея, которая позволила бы мне добавить условие, при котором объект не выбирался бы с подобъектом == null?Или предотвратить попытки доступа к свойству из объекта, который является нулевым?

РЕДАКТИРОВАТЬ:

Проверка будет выглядеть примерно так: list.OrderBy (x => (x.Address! =null)? x.Address.Street: string.Empty).

Поэтому мне нужно добавить нулевую проверку для каждого объекта между x и последним полем.Можно ли сделать это, используя эти методы?

РЕДАКТИРОВАТЬ 2:

Я пытался заменить

Expression.Property(expr, pi);

на

expr = Expression.Condition(
                Expression.Equal(expr, Expression.Constant(null)),
                Expression.Constant(String.Empty),
                Expression.Property(expr, pi));

Но, похоже, это не работает.Я получаю следующее исключение:

Argument types do not match

Любая идея, как я должен знать значение по умолчанию для поля, доступного через expr?

1 Ответ

0 голосов
/ 06 августа 2012

создайте нулевую константу в качестве типа свойства.

expr = Expression.Condition(Expression.Equal(expr, Expression.Constant(null, expr.Type)),
                Expression.Constant(String.Empty),
                Expression.Property(expr, pi));
...