首页 > 解决方案 > 在编译表达式之前测试空子

问题描述

我正在尝试通过 检索一个值Expression,但我有一个场景,模型上的子属性为 null 并且我得到一个NullReferenceException.

该场景发生在我以以下方式使用模型的情况下,x视图中的模型在哪里并且它不为空,但Contact属性为空:

x => x.Contact.Email

然后我使用以下方法检索该值:

public static FieldInfo Get<TModel, TProperty>(HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
{
    object value = null;
    if (html.ViewData.Model != null)
    {
        value = expression.Compile()(html.ViewData.Model);
    }

    // other code
}

如何调整此代码以测试子属性上的 null 还是不可能的?

标签: c#linq

解决方案


为了在我的IQueryable左外连接实现中处理这个问题,我使用了一个ExpressionVisitor替换null.membernull. 您可以在ExpressionEF/LINQ to SQL 支持的 .

public static class ExpressionExt {
    public static TE AddTestForNull<TE>(this TE orig) where TE : Expression => (TE)(new NullTestVisitor().Visit(orig));
}


/// <summary>
/// ExpressionVisitor to replace a obj.member Expression with a null test ((obj == null) ? null : obj.member)
/// </summary>
public class NullTestVisitor : System.Linq.Expressions.ExpressionVisitor {
    public override Expression Visit(Expression node) {
        if (node is MemberExpression nme)
            return Expression.Condition(Expression.MakeBinary(ExpressionType.Equal, nme.Expression.AddTestForNull(), Expression.Constant(null, nme.Expression.Type)),
                                        Expression.Constant(null, nme.Type),
                                        nme);
        else
            return base.Visit(node);
    }
}

然后,当您需要处理此类问题时Expression,只需继续AddTestForNull

value = expression.AddTestForNull().Compile()(html.ViewData.Model);

这将在每个级别添加测试 - 如果您有x => x.member.testMember,它将被替换为((x == null ? null : x.member) == null ? null : x.member.testMember).


推荐阅读