2014-07-18 66 views
3

這是我第一次編寫將用於大量幾何計算的小型不可變結構。我很想使用public readonly字段而不是private field/public getter組合。將公共只讀字段用於不可變結構而不是私有字段/公共getter對

public struct Vector4 
{ 
    public readonly float Angle, Velocity; 

    // As opposed to: 
    private float _Angle, _Velocity; 
    public float Angle { get { return (this._Angle); } } 
    public float Velocity { get { return (this._Velocity); } } 

    public Vector4 (float angle, float velocity) 
    { 
     // Once set in the constructor, instance values will never change. 
     this.Angle = angle; 
     this.Velocity = velocity; 
    } 
} 

它看起來更乾淨,並消除了額外的層(吸氣劑)。由於缺乏使用公共領域是不好的做法,這樣使用公共只讀領域會有什麼負面影響嗎?

請注意,我們只討論價值類型。例如,數組會暴露元素被調用代碼覆蓋。

UPDATE:

感謝所有的輸入。似乎沒有使用public readonly字段的情況下沒有使用數據綁定等情況。在我的基準測試中,執行時間下降了70%,這是一件大事。針對.NET 4,我會希望編譯器內聯getter-only屬性。基準測試當然在發佈配置中進行了測試,沒有附加調試器。

+0

正如@asawyer指出的那樣,這是我過去對結構所做的工作,儘管只讀是一個有趣的想法。 readonly背後的想法是它們只能通過聲明或構造函數來設置。由於結構被認爲是不可變的,所以對我來說這聽起來像個好主意。我希望能聽到某人知道他們在說什麼,以確定這是否是有效的事情:O – Kritner

+0

@asawyer請注意,自動屬性不能用在struct構造函數中,因爲您將立即得到「The'這個對象不能在其所有字段被賦值之前使用「。因此,如果你需要一個構造函數來爲結構的屬性賦值,那麼非自動屬性就是要走的路。 –

+1

在這種情況下,我期待.NET Framework獲得指導。框架中的結構是否使用字段或屬性?答案是屬性,所以我傾向於效仿。該框架只是真的使用字段的常量。所有其他條件相同的情況下,屬性的優勢在於能夠綁定,哪些字段不能,並且還允許您在將來更改實現而不更改接口。面向未來的方式不會受到傷害。 – jmcilhinney

回答

7

在沒有反射的純C#中,在您的案例中避免只讀字段的原因很少,我可能會自己選擇只讀字段。物業的大多數一般優點並不適用於此。那說...

任何使用反射來獲取屬性列表並對這些屬性起作用的東西,不會在字段(無論是否是隻讀的)下無需修改即可使用。

特別是,將屬性更改爲字段可能會導致數據綁定停止工作。它將繼續編譯而沒有任何問題,但它不會再按照你想要的那樣去做。如果您有任何此類代碼,或者您將來會預期此類代碼,則需要繼續使用屬性。

+0

提及數據綁定。並不是說它適用於我的案例,但您如何看待域的反射問題?還是你的意思是如果屬性更改爲字段? –

+1

@RaheelKhan數據綁定是一個使用僅查看屬性的反射的代碼示例。 'typeof(Vector4).GetProperties()'不會包含您的只讀字段;爲此,應該使用'typeof(Vector4).GetFields()'。如果(像數據綁定一樣)對'GetProperties()'的調用不在你自己的代碼中,那麼你就被卡住了。 – hvd

+0

+1一個很好的答案。特別是,「......如果你預計將來會有這樣的代碼......」 - 誰知道未來會怎樣?僅僅因爲這個原因,除非有非常嚴重的性能影響,否則我很難證明犧牲財產封裝是正當的。 70%聽起來很嚴肅,但如果班級只用了幾次,那絕對是微不足道的。環境規則。 –

0

自動屬性可能會有所幫助。

public struct Vector4 
    { 
    public float Angle { get; private set; } 
    public float Velocity { get; private set; } 

    public Vector4(float angle, float velocity) : this() 
     { 
     // Once set in the constructor, instance values will never change. 
     this.Angle = angle; 
     this.Velocity = velocity; 
     } 
    } 

[注:更新,使其編譯 - 感謝拉塞五卡爾森指出了這一點]

注意,這是完全一樣成爲具有支持字段的屬性,除非你是讓編譯器選擇它的名字(這將是一些'無法檢測'的字符串)。

這是什麼讓您關注房產?如果它是詳細的,那麼使用上面的自動屬性。如果你關心性能,那麼你有沒有測量性能對比領域的影響?

有趣的是,Jeffrey Richter在他的書CLR中通過C#表示他希望他們沒有被包含在CLR中。他說他更喜歡明確使用getXXX和setXXX方法。他認爲屬性語法很混亂。就個人而言,我看過Java代碼的工作原理,我更喜歡屬性語法。

我認爲值得一提的是readonly也可能會讓人困惑。在這種情況下,它是毫不含糊的,因爲我們正在處理整個價值類型,並且'在錫上說'。但是,如果這些是引用類型,那麼readonly只保護引用 - 也就是說,該字段必須始終引用同一個對象,但引用的對象本身可能會被突變,如果它被寫入允許的話。我懷疑許多沒有經驗的程序員被這種微妙的絆住了。

考慮到您衡量的性能優勢,我認爲您對使用公共只讀字段有合理的理由,這是一個判斷呼叫。權衡是讓你的類型的消費者與你的結構的內部緊密結合,實質上是犧牲封裝。對於這種在受控條件下並具有可靠性能優勢的簡單類型,這可能是合理的。

+1

這不會編譯。您不能在結構構造函數中設置自動屬性。 –

+0

我瞭解汽車性能並慷慨地使用它們。然而,在這種情況下,計算基準下降到30%的時間只有readonly字段而不是屬性。這對CPU密集型代碼來說是一個巨大的挑戰。 –

+0

@RaheelKhan你是否調用了DEBUG構建或RELEASE構建? –

5

準則,如「優先於公共領域的公共財產」是準則,而不是規則。

一些箱子的利弊使用字段的可能超過缺點

他的主要論據有領域,而不是:事實上,波多黎各馬里亞尼在說明一個這樣的場景,這在我看來長得像你的工作做得很好屬性是基本類型如Point,VectorVertex通常沒有非法值,所以幾乎不需要添加getter/setter圖層。

他也有很好的理由,因爲可變字段,但這不是你的情況。

但我想自己添加一個觀點,讓您考慮一下:您的類是否會用於數據綁定?數據綁定僅適用於屬性,而不適用於字段。

+0

感謝您的鏈接。在我的情況下,可變性不是一種選擇,因爲這些對象需要使用字典,哈希集等進行大量處理。不,這個代碼不適用於數據綁定或任何UI場景。 –

+0

@RaheelKhan那麼你的情況可能是一個很好的候選人使用公共只讀字段:) – dcastro

相關問題