Как создать «встроенный оператор if» с выражениями в динамическом выделении для проверки нуля - PullRequest
0 голосов
/ 20 декабря 2018

Как создать «встроенный оператор if» с выражениями в динамическом выделении для проверки на нуль

Мне было написано динамическое выражение выбора linq для вложенного свойства объекта, но оно выдает исключение, когда оно равно нулю,поэтому я хочу проверить, является ли это свойство нулевым или нет, это просто!

вот что я имею в виду:

X.Where(...)
 .Select(X => new Y{
    ...
    Z = X.Titles == null ? "" : [Linq]
    ...
}).FirstOrDefault();

вот что я написал

private static Expression GetLocalizedString(Expression stringExpression, SupportedCulture supportedCulture)
    {
        var expression = Expression.Parameter(typeof(APILocalizedString), nameof(APILocalizedString));

        var prop = Expression.Property(expression, nameof(APILocalizedString.SupportedCulture));
        var value = Expression.Constant(supportedCulture);
        var condition = Expression.Equal(prop, value);

        var where = Expression.Call(
            typeof (Enumerable),
            nameof(Enumerable.Where),
            new Type[] { typeof(APILocalizedString) },
            stringExpression,
            Expression.Lambda<Func<APILocalizedString, bool>>(condition, expression));

        var select = Expression.Call(
            typeof(Enumerable),
            nameof(Enumerable.Select),
            new Type[] { typeof(APILocalizedString), typeof(string) },
            where,
            Expression.Lambda<Func<APILocalizedString, string>>(
                Expression.Property(expression, nameof(APILocalizedString.Text)),
                expression
            ));

        var first = Expression.Call(
            typeof(Enumerable),
            nameof(Enumerable.First),
            new Type[] { typeof(APILocalizedString) },
            stringExpression);

        var defaultIfEmpty = Expression.Call(
            typeof(Enumerable),
            nameof(Enumerable.DefaultIfEmpty),
            new Type[] { typeof(string) },
            select,
            first);

        var firstOrDefault =
            Expression.Call(
            typeof(Enumerable),
            nameof(Enumerable.FirstOrDefault),
            new Type[] { typeof(string) },
            defaultIfEmpty);


        var nullCheck = Expression.Equal(stringExpression, Expression.Constant(null, stringExpression.Type));
        var result = Expression.IfThenElse(nullCheck, Expression.Constant(""), firstOrDefault);

        return result;
    }

вот что генерирует GetLocalizedString:

{IIF((X.Titles == null), "", X.Titles.Where(APILocalizedString => (APILocalizedString.SupportedCulture == EN)).DefaultIfEmpty(X.Titles.First()).Select(APILocalizedString => APILocalizedString.Text).FirstOrDefault())}

Выберите выражение

... bindings.Add(Expression.Bind(property, GetLocalizedString(Expression.Property(parameter, "Titles"), SupportedCulture.EN))); ...

и вот сообщение об ошибке:

System.ArgumentException: 'Argument types do not match'

Выберите свойство типа String

. Есть ли способ создать выражение, например X.Titles == null ? "" : [Linq]?

1 Ответ

0 голосов
/ 20 декабря 2018

Выражение, эквивалентное условному оператору C # ?:, равно Expression.Condition.В то время как Expression.IfThenElse, который вы используете, является эквивалентом блока C # if then else.

Оба метода возвращают ConditionalExpression с Test, IfTrue иIfFalse свойства заполнены.Разница в том, что результат Type для Condition является типом операндов, в то время как для IfThenElse это void, поэтому его нельзя использовать в деревьях выражений запросов.

Так что ответна ваш конкретный вопрос:

var result = Expression.Condition(nullCheck, Expression.Constant(""), firstOrDefault);

PS Как побочный узел, я получаю несколько ошибок из вашего фрагмента кода, поэтому мне пришлось переставить его таким образом, чтобы получить безошибка в строке выше:

private static Expression GetLocalizedString(Expression stringExpression, SupportedCulture supportedCulture)
{
    var expression = Expression.Parameter(typeof(APILocalizedString), nameof(APILocalizedString));

    var prop = Expression.Property(expression, nameof(APILocalizedString.SupportedCulture));
    var value = Expression.Constant(supportedCulture);
    var condition = Expression.Equal(prop, value);

    var where = Expression.Call(
        typeof(Enumerable),
        nameof(Enumerable.Where),
        new Type[] { typeof(APILocalizedString) },
        stringExpression,
        Expression.Lambda<Func<APILocalizedString, bool>>(condition, expression));

    var first = Expression.Call(
        typeof(Enumerable),
        nameof(Enumerable.First),
        new Type[] { typeof(APILocalizedString) },
        stringExpression);

    var defaultIfEmpty = Expression.Call(
        typeof(Enumerable),
        nameof(Enumerable.DefaultIfEmpty),
        new Type[] { typeof(APILocalizedString) },
        where,
        first);

    var select = Expression.Call(
        typeof(Enumerable),
        nameof(Enumerable.Select),
        new Type[] { typeof(APILocalizedString), typeof(string) },
        defaultIfEmpty,
        Expression.Lambda<Func<APILocalizedString, string>>(
            Expression.Property(expression, nameof(APILocalizedString.Text)),
            expression
        ));

    var firstOrDefault =
        Expression.Call(
        typeof(Enumerable),
        nameof(Enumerable.FirstOrDefault),
        new Type[] { typeof(string) },
        select);


    var nullCheck = Expression.Equal(stringExpression, Expression.Constant(null, stringExpression.Type));
    var result = Expression.Condition(nullCheck, Expression.Constant(""), firstOrDefault);

    return result;
}
...