2010-12-02 88 views
10

請解釋結構構造函數的以下錯誤。如果我將結構更改爲類 ,則錯誤消失。編譯錯誤。使用屬性struct

public struct DealImportRequest 
{ 
    public DealRequestBase DealReq { get; set; } 
    public int ImportRetryCounter { get; set; } 

    public DealImportRequest(DealRequestBase drb) 
    { 
     DealReq = drb; 
     ImportRetryCounter = 0; 
    } 
} 
  • 錯誤CS0188:之前所有的字段被分配到
  • 錯誤CS0843的「這個」對象不能使用:支持字段的自動實現的屬性 「DealImportRequest.DealReq」必須完全分配在控制返回給調用者之前。考慮從構造函數初始值設定項中調用默認構造函數。
+0

可能的重複http://stackoverflow.com/questions/2534960/c-struct-constructor-fields-must-be-fully-assigned-before-control-is-returned – Hps 2010-12-02 14:02:59

+0

@HPS,我不同意。雖然它涉及到與該問題相同的問題,但它與隱式字段相比(支持自動屬性)而不是明確字段的事實足以阻止某人看到這兩個問題相關的原因。這應該足以認爲他們不是重複IMO。 – 2010-12-02 14:29:55

回答

14

由於錯誤消息的建議,您可以通過從構造函數初始值設定項中調用默認構造函數來解決此問題。

public DealImportRequest(DealRequestBase drb) : this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

從語言規範:

10.7.3自動實現的屬性

當屬性被 指定爲自動 實現的屬性,一個隱藏的背襯 字段是自動可用於 的財產,並訪問器是 實施讀取並寫入 支持領域。 [...]由於 後臺字段不可訪問,因此只能通過 屬性訪問器讀取和寫入 ,即使在 包含類型中也是如此。 [...] 這 限制也意味着, 自動實現的屬性明確 分配結構類型只能 使用標準的 構造的結構,因爲 分配給物業本身 實現,需要的結構來絕對是 分配。這意味着用戶定義的 構造函數必須調用默認的構造函數 。

另一個(更詳細的)替代方法當然是手動實現屬性並在構造函數中自行設置支持字段。

請注意你在那裏的結構是可變的。 This is not recommended。我建議你或者讓類型成爲一個類(你的編譯問題應該馬上消失),或者使類型不可變。假設您提供的代碼是整個結構,最簡單的方法就是使setter成爲私有的(get; private set;)。當然,你也應該確保你不會在結構中添加任何依賴私有訪問修改字段的變異方法。或者,您可以使用readonly支持字段替換屬性,並完全擺脫setters。

3

你的代碼等同於以下代碼:

public struct DealImportRequest 
{ 
    private DealRequestBase _dr; 
    private int _irc; 
    public DealRequestBase DealReq 
    { 
     get { return _dr; } 
     set { _dr = value; } 
    } 
    public int ImportRetryCounter 
    { 
     get { return _irc; } 
     set { _irc = value; } 
    } 
    /* Note we aren't allowed to do this explicitly - this is didactic code only and isn't allowed for real*/ 
    public DealImportRequest() 
    { 
     this._dr = default(DealRequestBase); // i.e. null or default depending on whether this is reference or value type. 
     this._irc = default(int); // i.e. 0 
    } 
    public DealImportRequest(DealRequestBase drb) 
    { 
     this.DealReq = drb; 
     this.ImportRetryCounter = 0; 
    } 
} 

現在,所有我在這裏所做的是刪除語法糖是:

  1. 實現自動屬性。
  2. 計算出哪些成員處理相對於this
  3. 提供所有struct s默認無參數構造函數。

前兩個是可選的(你可以明確他們寫,如果你願意),但第三個是不是 - 我們不允許我們自己寫的代碼爲struct的參數的構造函數,我們一起去一個像上面代碼中那樣工作的工具會自動提供給我們。

現在,看看這裏,突然兩個錯誤的含義變得清晰了 - 您的構造函數在分配字段(錯誤188)之前隱式使用this,而那些字段是支持自動屬性(錯誤843)的字段。

這是不同自動功能的組合,通常我們不必考慮,但在這種情況下效果不佳。我們可以通過下面的在843錯誤信息的建議,並調用默認的構造函數的顯式構造的一部分,解決這個問題:

public DealImportRequest(DealRequestBase drb) 
    :this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

關於我的擴展上面代碼的版本考慮到這一點,你可以看到這解決了這個問題,因爲它會在繼續進行之前調用分配給後臺字段的構造函數。

0

我會建議不要使用自動屬性的結構,除非你有充分的理由使用它們。在讀寫屬性中包裝類字段非常有用,因爲它使得實例可以控制可以讀取或寫入的環境,並在發生讀取或寫入時採取行動。此外,對象實例中的代碼可以識別正在執行的實例,並且因此可以僅在讀取和寫入特定實例時才執行特殊操作。在類的早期版本中使用自動屬性將使未來版本的類可以使用包含上述優點的手動實現的屬性,同時保留與已編譯的客戶端代碼的兼容性。不幸的是,將一個struct字段封裝在一個讀寫屬性中並不能提供這些好處,因爲一個結構實例的字段可以被複制到另一個結構中,而沒有任何實例在這個問題上有任何發言權。如果一個結構的語義允許在大多數情況下使用任意值來編寫一個屬性[就像自動屬性一樣],那麼任何合法的替換在語義上都等價於一個字段。