linq 如何在动态选择中使用表达式创建“内联if语句”以进行空值检查

qzwqbdag  于 2022-12-06  发布在  其他
关注(0)|答案(1)|浏览(98)

如何在动态选择中创建带有表达式的“内联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'
Select属性的类型为String
有没有办法创建一个类似X.Titles == null ? "" : [Linq]表达式?

anauzrmj

anauzrmj1#

C#条件?:运算子的运算式对等用法是Expression.Condition。而您使用的Expression.IfThenElse则是C#if then else区块的对等用法。
这两个方法都会传回ConditionalExpression,并填入TestIfTrueIfFalse属性。差异在于Condition的结果Type是算子的类型,而IfThenElse的结果是void,因此无法用于查询表示式树形结构。
所以你这个具体问题的答案是:

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

P.S.作为一个边节点,我从代码片段中得到了几个错误,所以我不得不像这样重新排列它,以便在上面的行中得到w/o错误:

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;
}

相关问题