带有select子句的System.NullReferenceException

时间:2012-02-23 15:34:28

标签: c# validation asp.net-mvc-2 nullreferenceexception

亲爱的社区:D

现在我正在开展我的第一个大项目并且有点卡住了。 我正在尝试验证一些输入。

因此我正在使用此功能:

public static Validatable<string> RequiredOr(this Validatable<string> that, Func<Validatable<string>, bool> func)
{
    return that.DoEvaluate && !(func(that) || that.Value != null)
            ? that.Error(ML.Get("Validation", "IsRequired"))
            : that;
}

对于正常验证我正在使用:

public Validatable<TProperty> Validate<TProperty>(
        Expression<Func<TEntity, TProperty>> expr)
    {
        return new Validatable<TProperty>(
            new ErrorTrackerWrapper(ErrorTracker, expr.Body), expr.Compile()(Value));
    }

这部分称为“RequiredOr”功能:

var header = from name in v.Validate(it => it.Name).Required().MaxLength(Constants.String.NameLength)
                     from startDate in v.Validate(it => it.StartDate).Required().After(DateTime.Today)
                     from endDate in v.Validate(it => it.EndDate).Required().After(DateTime.Today)
                     from endTime in v.Validate(it => it.EndTime).BlockErrors().Required().ReplaceIfInvalid(new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 23, 30, 0))
                     from requestedCurrency in v.Validate(it => it.RequestedCurrency).Required()
                     from language1 in v.Validate(it => it.Language1).Required()
                     from language2 in v.Validate(it => it.Language2)
                     from language3 in v.Validate(it => it.Language3)
                     from hasMoreInformation in v.Validate(it => it.HasMoreInformation)
                     // TODOJP: If "hasMoreInformation" is true, then "moreInformationEmail" has to be required.
                     from moreInformationEmail in v.Validate(it => it.MoreInformationEmail).IsEmail()//.RequiredOr(p => !hasMoreInformation)
                     from isAnonymous in v.Validate(it => it.IsAnonymous)
                     select new AnnouncementHeader(
                        currentUser,
                        type,
                        name,
                        startDate,
                        endDate.SetTime(new Time(endTime.Hour, endTime.Minute)),
                        isAnonymous,
                        infoField,
                        requestedCurrency,
                        language1,
                        language2,
                        language3,
                        hasMoreInformation,
                        moreInformationEmail);

到目前为止,这是正确的,但有些如何,它一直告诉我“RequiredOr”部分中的“hasMoreInformation”是一个NullReferenceException。

我能够将错误追溯到“RequiredOr”函数。

我想检查“HasMoreInformation”是否为真,然后将字段设置为“必需”。

我希望你的家伙明白我要告诉你的是什么。 非常感谢你的帮助。

1 个答案:

答案 0 :(得分:0)

对于可能为空的对象,您必须在测试该字段是否为真之前测试该字段是否存在。违反规则的后果是空引用异常。这就是它的工作原理。

如果该项可以为空,则始终存在空值。如果你默认值,你可以不这样做,但是默认值必须具有单一含义,并不意味着“它可以是默认值”和“它可以由用户显式设置”。

如果默认值没有意义,那么在验证之前,您假设一个空对象表示有效或无效。

由于我的上下文很少,我建议以长篇形式写出来解决问题。然后,您可以重新考虑延迟执行样式(LINQ)。我之所以这么说,是因为你似乎只想选择有效的,当项目不为空时以及其他没有明确说明的内容(基于关于之后需要检查的评论)。 LINQ它之前解决问题。

新:在LINQ-up解决方案之前仍然坚持最后一行解决方案(我将在这里包括所有形式的延迟执行,而不仅仅是LINQ)。

如果没有我在语句上花费大量时间,你有一些LINQ和一些扩展方法(带有链接方法的流畅语法,等等,等等)。所有这些都是延迟执行。如果您要下拉符号并弹出堆栈,您可能会发现延迟执行的顺序是问题的一部分。它通常是调试抽象堆的唯一方法。 (是的,我已经看到了一个带有函数指针和扩展方法的47行嵌套LINQ语句)

当你使用流体编程风格时,你实际上是在运行伪IoC类型的模式,因为最右边的方法会转到下一个方法,直到你一直向左移动。非常糟糕的类比解释,所以我可能会得到纠正,但是你正在使用函数指针来保持流程的正确方法。例如:

Colonel.Sanders.Loves.Chicken( “炒”);

函数指针,扩展方法和RX,哦,我的!从哲学的角度来看相当简洁的东西,但如果你真的不明白它是如何工作的,那就容易出现糟糕的juju。它通常会产生非常清晰的语法,但会产生调试噩梦。

如果你进一步坚持在LINQ声明中选择膳食计划或快餐店,你会得到很多来自不同方向的延迟声明。并且,如果一个位的顺序不正确,则某些代码会在必要的前导之前运行。由于LINQ和扩展方法使用不同的方法,因此将它们混合会增加以不正确的顺序运行位的可能性。使用符号进行调试通常是唯一的方法,因为整个延迟抽象的blob在运行时被“编译”。

所以,要结束这篇长篇文章,你需要a)调试并弄清楚为什么你得到空引用(很可能是你的延迟执行堆栈中的调用错误)或b)首先解决问题使用非延迟方法(或者一次运行一个延迟的goo?)。