2012-02-23 90 views
1

你好心愛的社區:DSystem.NullReferenceException與選擇子句

現在我正在對我的第一個大項目,我有點卡住了。 我想驗證一些輸入。

因此我使用這個功能:

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」是否爲true,然後將該字段設置爲「必需」或不。

我希望你的傢伙明白我想告訴你什麼。 並且非常感謝您的幫助。

+0

請發佈Validate()的代碼,也請發佈整個linq查詢。現在很難猜測發生了什麼。標題說select子句有問題,但是你沒有包含select子句。 – phoog 2012-02-23 15:41:58

+0

我更新了代碼。 錯誤不在select子句中 - 對不起 - 它在「moreInformationEmail」的「RequiredOr」部分。 (看看評論部分) – KampfFussel 2012-02-23 15:50:38

+0

對不起,我還是很困惑。 'Validate()'返回一個IEnumerable嗎?還是它返回一些其他類型的查詢理解語法? – phoog 2012-02-23 16:00:36

回答

0

對於可能爲null的對象,您必須先測試該字段是否存在,然後再測試它是否爲真。違反規則的後果是空的ref例外。這就是它的工作原理。

如果該項目是可以爲空的,則總是有可能爲空。如果您默認值,則可以不這樣做,但默認值必須具有單一含義,而不是意味着「可以是默認值」和「可以由用戶明確設置」。

如果默認值沒有意義,那麼您在驗證之前假設一個空對象,或者表示有效或無效。

由於我的上下文很少,因此我建議以長的形式寫出來解決問題。然後您可以重新考慮延遲執行風格(LINQ)。我這樣說是因爲你似乎只想選擇有效的,當項目不是空的和其他沒有明確說明的東西(基於關於後面檢查的評論)。在LINQ之前查看問題。在LINQ解決方案之前仍然堅持最後一條解決方案(我將在這裏包括所有形式的延期執行,而不僅僅是LINQ)。如果沒有我真的在聲明上花費了大量的時間,你有一些LINQ和一些擴展方法(帶鏈接方法的流體語法,等等,等等)。所有這些都是延期執行。如果您要下拉符號並彈出堆棧,您可能會發現延期執行的順序是問題的一部分。它通常是調試抽取一堆抽象的唯一方法。 (是的,我已經看到一個47行嵌套LINQ語句與函數指針和擴展方法)

當您使用流體編程風格,你基本上運行一個僞IoC類型的模式,因爲最右邊的方法獲取過去到下一個方法,直到你一路走到左邊。非常差的類比解釋,所以我可能會糾正,但你正在使用函數指針來保持正確的方法流。例如:

Colonel.Sanders.Loves.Chicken( 「炒」);

函數指針,擴展方法和RX,哦,我的!從哲學的角度來看,整潔的東西,但如果你真的不明白這是如何工作的,容易產生不好的感覺。它通常會提供非常清晰的語法,但會產生調試噩夢。

如果您在LINQ聲明進一步堅持選擇膳食計劃,或快餐店,你最終得到了很多遞延咕來自不同方向。而且,如果一個位的順序不正確,那麼一些代碼會在必要的前兆之前運行。由於LINQ和擴展方法使用不同的方法,因此混合它們會增加以不正確的順序運行位的可能性。使用符號進行調試通常是破解的唯一方式,因爲整個延遲抽象的一團在運行時會被「編譯」。因此,要結束這篇較長的文章,您需要a)通過調試並找出爲什麼你得到null ref(很可能是延遲執行堆棧中的一些調用錯誤)或者b)解決問題首先使用非延遲方法(或者可能每次運行一個推遲的goo?)。

+0

該項目不可爲空 - 它只能是真或假,默認爲假 – KampfFussel 2012-02-23 15:57:32

+0

看起來,您正試圖完成對該集合的驗證,然後在一次調用中完成數據整形。最重要的是,您正在使用不同的方式來延遲執行,方法是將LINQ構造與堆疊的擴展方法鏈接在一起。添加了其餘部分以供回答。 – 2012-02-23 16:18:42

+0

非常感謝您的解釋。我認爲這就是我需要的。 就像我在我的文章(編輯)中,我能夠調試到'RequireOr()'函數,並注意到這是'func(that)'的問題。 – KampfFussel 2012-02-23 16:42:11