2010-11-21 81 views
2

我目前正試圖以檢查其是否使用帶有「的MyMethod」之前一提的是空:C# - 「對象引用不設置到對象的實例」

if (School.ClassRoom.Pupil.Age != null) 
     { 
      MyMethod(School.ClassRoom.Pupil.Age); 
     } 

不過,我m仍然在第一行得到「對象引用未設置爲對象的實例」,因爲Age不僅是空的,而且Pupil和ClassRoom也有時也是空的。

我得到了同樣的問題,使用Try,Catch,最後,因爲我在Try段代碼中得到了同樣的錯誤。

我不想檢查每個ClassRoom爲null,然後每個Pupil爲null,然後每次我想使用此方法時,每個Age爲null。

有沒有更簡單的方法來做到這一點?

+0

你如何填寫School.ClassRoom數據?填充時,不允許NULL行可能是一個解決方案? – 2010-11-21 08:47:39

+0

順便說一句,你的標題似乎並不合適。沒有任何混淆你所得到的例外。 – 2010-11-21 09:13:48

+0

如果可能的話,我希望能夠繼續使用空類,因爲這是一個相當複雜的數據結構的一部分,如果我開始有所有的空值的新實例,那麼我認爲內存使用率將通過屋頂。 – Caustix 2010-11-21 09:55:20

回答

5

這聽起來像是你在類似Groovy的無效解引用操作符之後,它會讓你編寫if (School?.ClassRoom?.Pupil?.Age != null)--但是C#沒有這樣的東西。

恐怕你檢查每個屬性爲無效,假設它可以空:

if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null 
    && School.ClassRoom.Pupil.Age != null) 
{ 
    MyMethod(School.ClassRoom.Pupil.Age); 
} 

當然,你可以把這個整個if塊包括方法調用本身一個輔助方法,然後調用它。

這就是假設它對每個屬性有效,以 null開頭。如果你能夠設計你的類,那麼甚至不允許使用空值 - 並且你在contsructors等中驗證了這一點 - 你的代碼很可能會變得更加乾淨。

值得注意的是,這裏有兩種替代方法 - 克里斯在另一個答案中提出的方法是爲每個屬性創建一個「默認」對象;我通常發現總是需要在構造函數中提供「真實」值更好。沒有真實數據的默認對象最終會導致比NullReferenceException問題難以跟蹤的錯誤,因爲您可以長時間快樂地處理「虛擬」數據,並在最後得到錯誤的結果。當然,有些時候是正確的選擇,但是 - 尤其是當涉及到收藏時。這取決於實際情況。

編輯:賽義德建議在評論中的擴展方法。我想這會是這樣的:(適當調整類型)

public static int? PupilAgeOrNull(this School school) 
{ 
    return school != null && 
      school.ClassRoom != null && 
      school.ClassRoom.Pupil != null 
      ? school.ClassRoom.Pupil.Age : null; 
} 

我肯定更喜歡嘗試讓一切非空別處的想法,但如果你需要它,這將做到這一點。雖然我感覺不對。這種直覺的核心是你正在導航三個或四個屬性 - 這對我來說就像是違反了Law of Demeter。現在我不是那種對這種事情有教條意義的人,但是在School上加上擴展方法對我來說太過於具體,對於如此長的屬性路徑。

另一種選擇 - 這也是有些討厭,IMO - 是寫三個不同的推廣方法:

public static ClassRoom ClassRoomOrNull(this School school) 
{ 
    return school == null ? null : school.ClassRoom; 
} 

public static Pupil PupilOrNull(this ClassRoom classRoom) 
{ 
    return classRoom == null ? null : classRoom.Pupil; 
} 

public static int? AgeOrNull(this Pupil pupil) 
{ 
    return pupil == null ? null : pupil.Age; 
} 

然後,你可以寫:

int? age = School.ClassRoomOrNull().PupilOrNull().AgeOrNull(); 
if (age != null) 
{ 
    MyMethod(age); 
} 

這意味着,在School擴展方法並不是那麼具體。你仍然有一長串的方法調用,我仍然試圖重新設計,以儘可能避免這種情況,但至少從SchoolSchool.ClassRoom.Pupil.Age沒有那麼緊密的關係。

+0

他希望不要這樣做,而不是'如果'寫一個擴展方法 – 2010-11-21 09:00:10

+0

@Saeed:嗯,他在哪裏提及擴展方法? – 2010-11-21 09:00:58

+1

if(School.IsNullAge())寫這樣一個函數很容易,他爲什麼要提這個,他不喜歡醜陋的代碼 – 2010-11-21 09:02:45

1

給你顯示的代碼,沒有更簡單的方法。您需要檢查每個組件。

if (School != null && School.ClassRoom != null 
    && School.ClassRoom.Pupil != null 
    && School.ClassRoom.Pupil.Age != null) 
{ 
    ... 
} 

但是,您可以編寫代碼,以這樣的方式所述成員從未null。這樣,你可以避免不必檢查null。例如

對於
class School 
{ 
    private ClassRoom _classRoom = new ClassRoom(); 

    public ClassRoom ClassRoom 
    { 
    get {return _classRoom;} 
    } 
} 

這會給學校的空教室裏下手,所以它不是null,不能設置爲null外班的,因爲物業沒有一個二傳手。你可以將這個概念向前推進,你的學生列表(我認爲這將是一個列表)可以是一個空列表而不是空實例等。

1

「空對象模式」可以幫助你解決問題。閱讀here

所以,你可以有NullSchool,NullClassRoom,NullPupil,NullAge。

然後,你永遠不需要檢查空的東西,而是你可以在MyMethod中只有一個檢查(或方法,如Age類中的IsValid(),ofcourse虛擬)拒絕一個年齡,如果它是無效的。

+0

那麼它*可能*來救援。這取決於是否真的*是一個明智的「空」版本。正如我在答覆中所寫的,提供虛擬數據很容易導致難以診斷的問題。 – 2010-11-21 09:02:03

2

Here表達樹是一個不錯的和優雅的解決方案。 試試吧,盡情享受吧!

相關問題