猿问

在编译表达式之前测试空子

我正在尝试通过 检索一个值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 还是不可能的?


凤凰求蛊
浏览 112回答 2
2回答

慕盖茨4494581

为了在我的IQueryable左外连接实现中处理这个问题,我使用了一个ExpressionVisitor替换null.member为null. 您可以在ExpressionEF/LINQ to SQL 支持的 .public static class ExpressionExt {&nbsp; &nbsp; 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 {&nbsp; &nbsp; public override Expression Visit(Expression node) {&nbsp; &nbsp; &nbsp; &nbsp; if (node is MemberExpression nme)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.Condition(Expression.MakeBinary(ExpressionType.Equal, nme.Expression.AddTestForNull(), Expression.Constant(null, nme.Expression.Type)),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression.Constant(null, nme.Type),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nme);&nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return base.Visit(node);&nbsp; &nbsp; }}然后,当您需要处理此类问题时Expression,只需继续AddTestForNull:value = expression.AddTestForNull().Compile()(html.ViewData.Model);这将在每个级别添加测试 - 如果您有x => x.member.testMember,它将被替换为((x == null ? null : x.member) == null ? null : x.member.testMember).

Helenr

您是否可以调整 Get(..) 方法以使用 Func 而不是表达式?表达式不允许 Null Coalescing 或 Null Propagation 运算符。但是函数可以。//Yourspublic static FieldInfo Get<TModel, TProperty>(HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) { ... }//Potential solution for youpublic static FieldInfo Get<TModel, TProperty>(HtmlHelper<TModel> person, Func<TModel, TProperty> func) { ... }表达式不允许 Null Coalescing 或 Null Propagation 运算符。但是函数可以。请原谅类型的差异。我正在使用我当时最容易获得的东西来为你创建一个具体的例子。请注意,调用的是 Invoke() 方法而不是 Compile()public static object Get<Person, TProperty>(Person person, Func<Person, TProperty> func){&nbsp; &nbsp; object result = null;&nbsp; &nbsp; if (person != null)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; result = func.Invoke(person);&nbsp; &nbsp; }&nbsp; &nbsp; return result;}示例使用var personNoContact = new Person { Contact = null };var result = Get(personNoContact, x => x.Contact?.Email.EmailAddress ?? "");以下类用于测试public class Person{&nbsp; &nbsp; public Contact Contact { get; set; }}public class Contact{&nbsp; &nbsp; public Email Email { get; set; }}public class Email { public string EmailAddress { get; set; } }
随时随地看视频慕课网APP
我要回答