2012-03-29 62 views
2

在C#中使用對象初始值設定項時,是否可以執行規則或引發錯誤?我想拋出一個編譯器錯誤或警告,如果一個對象被初始化但缺少某個屬性。對象初始值設定程序強制編譯錯誤

public class Party 
{ 
    public string Name { get; set; } 
    public string Date { get; set; } 
    public Location Location { get; set; } 
} 

public class SignUpForParty 
{ 
    public void DoSomething() 
    { 
     Party party = new Party() 
     { 
      Name = "New Years Party!", 
      Date = "Dec 31, 1999" 
      // Show WARNING/ERROR here because no Location given 
     }; 
    } 
} 

本質上,我正在尋找一種方法來確保所有類型爲Party的對象都使用每個實例的有效數據創建。

很明顯,我可以用重載的構造函數做到這一點,但在某些情況下,我有很多屬性和編寫構造函數來匹配是混亂的。我想遵循更清晰的C#風格。

Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty 
+1

你可以把每個構造函數參數放在它自己的行上,而且看起來很相似。你提到構造函數重載,但你也說你想要*所有*屬性設置,這表明一個超級構造函數。 – dlev 2012-03-29 01:16:17

+0

感謝您的答案。我混淆了對象發起者與構造函數。我想要兩全其美 - 建立一個強制執行的對象,但要有簡單的對象啓動器風格。我不想要一堆超級構造函數。 What @ reed-copsey在我的場景中也是如此,因爲我們需要的是構造函數,可選的東西應該留給啓動器。 – daviddeath 2012-03-29 02:53:12

回答

4

顯然我可以用重載的構造函數做到這一點,但在某些情況下,我有很多屬性和編寫構造函數來匹配是凌亂的。我想遵循更清晰的C#風格。

對象初始值設定項實際上不應被視爲寫入構造函數的替代方法。

如果你有這樣的要求,你應該總是在你的類型中包含構造函數。創建一組默認的構造函數(或者在一個構造函數上使用可選參數)是一個好主意,它至少能夠保證對象始終以有效的,有意義的狀態創建。

對象初始值設定對可選屬性有幫助,但不應該依賴於類型本身的要求。

3

您無法強制每個屬性都使用對象初始值設定項進行初始化。

即使可以,對象的使用者也可以提供默認值(0,null,...)。根據您的需要,考慮在關鍵時間驗證對象狀態(例如,在可以將其保存到數據庫之前)。

如果你走這條路線,看看IDataErrorInfo接口。

2

如果您的類型僅在設置了2個屬性時無效,那麼您需要修復您的設計,而不是發出錯誤。

您提供了一個默認的構造函數,它告訴我,在初始化後我不必設置任何東西來使用該對象。你爲每個屬性提供getter和setter,再次隱式告訴你的類的用戶可以設置,但不能設置另一個。

如果情況並非如此,那麼我建議你提供一個構造函數,它迫使我提供所有三個值。是的,我仍然可以使用(null, null, null),但是您可以檢查並輸出錯誤。

此外,如果PropertyA取決於PropertyB然後要麼

A)只有它們中的一個應該有一個設置器,或

B)應該有邏輯在每個設定器正確初始化其它值改變後。

這是一個設計問題,而不是語言問題。您不能強制初始化器語法的工作方式與其指定方式不同。

Obj p = new Obj(1,2,3,... n); //太多漂亮的屬性

代碼不應該是'漂亮',它應該工作。即便如此,一個接受幾個參數的構造函數是'醜陋'?咦?不要購買時髦的廢話,編寫可行的代碼並運行良好。

+0

同意所有觀點,謝謝。 「...你提供了一個構造函數,它迫使我提供所有三個值」 - 我可能會更好地理解我的問題:「我可以提供帶構造函數的構造函數的行爲嗎?」我瞭解到,這不是。 – daviddeath 2012-03-29 03:11:37

0

我可以看到這個實現的唯一方法是當對象初始化器完成時引發了一些事件(或等價物)。目前有一個Connect request爲這個效果。

不幸的是,我並沒有獲得晉級的.NET 4.5:

謝謝您的建議。

這是一個很棒的主意,它具有很好的屬性,它不會添加到語言表面 - 它只是使對象初始化變得更加智能。原則上這可能會使其成爲一個突破性的改變,但這是我們可以研究的。

不幸的是,我們不能再添加到我們目前正在構建的版本中,所以我將解決此問題。但是,我正在捕獲關於我們未來討論的功能列表的建議。

再次感謝!

的Mads託格森,C#語言PM

也許這將使它的方式進入.NET 5+。

+0

這是一個非常有趣的想法。在很多方面,這幾乎是我正在尋找的。 – daviddeath 2012-03-29 02:49:33

+0

@daviddeath - 不幸的是,目前沒有提供這種功能的解決方法,所以我只能建議對連接請求進行投票,希望它能夠進入下一個版本。我認爲今天唯一可行的(考慮到我們目前的限制)將是使用所提出的想法。也許不久之後。 – 2012-03-29 02:54:07

0

怎麼樣Code Contracts?這將斷言你不僅分配了一個值,還可以指定有效的範圍。

或者僅在運行時使用調試版本進行檢查,您可以使用Debug.Assert(...)調用實現與上述相同的調用。