2012-02-21 87 views
-1

想象一下,我有一個帶有X和Y座標的Point結構。 現在我有構造函數:Point(int x,int y)。結構 - 儘可能快地更改值

問題:我還應該添加名爲Point.SetXY(int x,int y)的方法嗎?

例如:

// I have some point 
point = new Point (5,5); 

// and I wanna change some values 
point = new Point (7,7); 

// or maybe should I do like this? 
point.SetXY (7,7); // is it faster? 

,因爲我知道這是更快,因爲ü不類需要在堆等

但也許對於結構,它不創造物質新的實例?

+1

你的基準測試表明速度更快? – 2012-02-21 16:01:51

+0

我不知道如何使用基準。無法一次學習所有內容。 – zgnilec 2012-02-21 16:02:59

+1

您是否有理由相信它在您的應用程序中有所不同?這聽起來像是過早的優化。 – 2012-02-21 16:04:09

回答

2

我思,你可以通過

point.X = 7; 
point.Y = 7; 

實現呢?這是最快的

+0

但這是非常錯誤的。 – SLaks 2012-02-21 16:06:50

+0

我知道這是最快的,但我優先考慮1行代碼來設置它。 – zgnilec 2012-02-21 16:13:56

+0

好的,我現在做了測試,兩種樣式都是等於,設置器樣式和構造器樣式爲2000,000,000循環= 17秒。你的風格直接訪問X和Y = 5秒,所以你的答案是最好的。謝謝。 – zgnilec 2012-02-21 16:36:09

4

除非有很好的理由,否則我會建議讓你的結構體不可變 - 只需在需要時用新的X和Y值創建一個新的結構體。

有關可變結構可能違反直覺的示例(或evil(取決於與創意許可有關的度量標準))Eric Lippert對此主題有a very good blog post

+0

我正在使用這樣的結構:我有一個類'Bullet'(示例),並且在這個類中我有一個'Point position';所以我認爲我很安全,因爲如果alwyas按照課程反對這個領域。 – zgnilec 2012-02-21 16:16:42

+0

該博客帖子涉及其方法變異「this」的結構,這確實有問題。有些人似乎認爲'這個'變異的結構是有問題的,或者一些非常早期的編譯器可能會在結構暴露出字段時生成愚蠢的代碼,這是一般的可變結構的一個論據,但我只是沒有看到它。 – supercat 2012-02-22 20:08:57

1

的Structs暴露字段是不是邪惡。雖然一些非常老的編譯器會接受類似的代碼:

 
List<Point> myList; 
myList[4].X = 5; 

這將複製myList中[4]爲臨時結構,修改臨時結構領域X,然後拋出修改後的結構遠,使得結構不變是一種確保編譯器能夠對上述構造進行攻擊的方法,確保編譯器在這些代碼中發聲的更好方法是將編譯器更改爲禁止寫入臨時結構的字段。由於這些代碼長時間被編譯器禁止,因此暴露域的結構通常是保存具有固定數量的獨立數據項(例如Point,Rectangle等)的東西的最佳方式。

什麼是問題是構造函數或屬性設定器以外的函數修改this的結構。雖然編譯器會認識到寫入someStructProperty.someField正在嘗試修改someStructProperty,並且在這種修改實際上不起作用的情況下將禁止它,但不幸的是,編譯器不知道someStructProperty.MutatingFunction()會嘗試修改臨時實例結構。因此編譯器會允許這樣的代碼,儘管它實際上不能按預期工作。如果函數應該修改一個結構「in place」,我會建議作爲一種補救措施,那就是定義一個靜態方法,它將結構的一個實例作爲參數ref。例如,SetPointXY(ref Point pt, int x, int y)。編譯器會將結構的傳遞視爲ref參數作爲修改該結構的嘗試,並且只會在實際工作的情況下允許它。

請注意,從性能的角度來看,只有單獨編寫struct字段不會是更新結構的最快方法,那就是當大部分結構匹配默認值或其他預設值時,現有的結構。可能有一些情況下,用一個預先存在的實例覆蓋一個結構會更快,然後編寫應該包含不同內容的字段,但通常我會建議應該使用方法或函數來僅在更新結構時纔會更新結構這樣做的代碼比單獨設置字段的代碼更具可讀性。如果AreaCodePhoneNumber類型的公共字段,則somePhoneNumber.AreaCode = "847";的效果遠遠超過somePhoneNumber = new PhoneNumber("847", somePhoneNumber.Exchange, somePhoneNumber.Number, somePhoneNumber.Extension);的效果。除其他外,必須研究整個結構以瞭解後者是否會改變AreaCode以外的任何字段。另一方面,如果一個人的目標實際上是一個空白的結構,除了一些全新的數據,那麼使用構造函數或工廠方法可能有助於澄清這樣一個事實:如果單獨覆蓋結構的所有字段,則必須研究整個結構以知道沒有任何字段可以保持不變。