2010-12-12 111 views
40

我應該在任意的結構實現什麼成員作如下分配可能:如何初始化結構?

public struct MyStruct { 
    String s; 
    Int length; 
} 

MyStruct myStruct = new MyStruct { s = "Hello", length = 5 }; 

// Now, I want the following code to set the 's' to "Lol" and the 
// length to 3 (length of "Lol"). The second part should be done 
// automatically. 
myStruct = "Lol"; // Or myStruct = String("Lol"); 

應該如何進行?

+4

請不要製作可變結構。 http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil – Ani 2010-12-12 02:25:57

+0

'字符串已經知道它們的長度。你爲什麼需要這樣的結構? – 2010-12-12 02:31:51

+0

@Karl Knechtel:我認爲這是一個顯示原理的例子。顯示的代碼甚至沒有編譯... – Guffa 2010-12-12 02:44:56

回答

72

您使用將字符串值轉換爲結構值的隱式運算符:

public struct MyStruct { 
    public string s; 
    public int length; 

    public static implicit operator MyStruct(string value) { 
    return new MyStruct() { s = value, length = value.Length }; 
    } 

} 

示例:

MyStruct myStruct = "Lol"; 
Console.WriteLine(myStruct.s); 
Console.WriteLine(myStruct.length); 

輸出:

Lol 
3 
+0

我在這裏可以看到的問題是struct的desvirtualization ...當你使用'new'操作符來返回結構時,這個操作符會把數據放在堆中...所以也許它更好地使用這個代碼作爲靜態類(所以有一個程序員的代碼清除)...並且事物獲得一致性... – ZEE 2017-11-08 03:36:10

+0

@ZEE:'new'運算符不會爲結構體分配堆。實際上沒有任何無參數的構造函數可供調用,它只是用於創建結構值的C#語法。 – Guffa 2017-11-10 14:55:03

0

你的結構可以有方法和屬性......爲什麼不嘗試

public struct MyStruct { 
    public string s; 
    public int length { return s.Length; } 
} 

修正 @ Guffa的回答表明,它是可能的...更多資訊:http://www.codeproject.com/KB/cs/Csharp_implicit_operator.aspx

+0

是的,這是可能的。 – Guffa 2010-12-12 02:32:02

+0

@Guffa:有趣的答案...我沒有考慮隱式算子。 – 2010-12-12 02:39:16

4
  1. 將 「長度」 曾經從 「S」 的實際長度偏差。如果答案是否定的,那麼你不需要存儲長度,因爲字符串已經存儲了它們的長度,並且你可以調用s.Length。

  2. 爲了得到你要的語法,你可以實現一個「隱性」操作符,像這樣:

    static implicit operator MyStruct(string s) { 
        return new MyStruct(...); 
    } 
    
  3. 隱含的經營者會工作,不管你是否讓你的結構可變與否。

7

結構類型應該,每當實際的,要麼都它們的狀態的包封在其中可以獨立地被設定爲是有效的其各自的類型,或者表現爲一個單一的統一值的任何值的公共字段,其可以只能通過構造函數,工廠,方法來設置賭注,或者通過將結構的實例作爲明確的ref參數傳遞給其公共方法之一。與一些人所聲稱的相反,如果一個結構具有公共字段,那麼它應該表示一組值,這些值可能被單獨操作或作爲一組傳遞(例如一個點的座標)。從歷史上看,有公共財產製定者的結構存在問題,並且希望避免公共領域(意味着應該使用制定者),這使得一些人認爲應該完全避免可變結構,但是領域沒有屬性存在的問題。事實上,暴露域結構是鬆散自變量集合的理想表示,因爲它只是一個鬆散的變量集合。

然而,在您的特定示例中,您的結構的兩個字段似乎不應該是獨立的。有三種方式你的結構可以合理地設計:

  • 你可以有唯一的公共領域是字符串,然後有一個只讀的「助手」屬性稱爲length如果字符串這將報告其長度非空,或者如果字符串爲null,則返回零。

  • 您可以讓結構不暴露任何公共字段,屬性設置器或變異方法,並且在對象的構造函數中指定唯一字段的內容(私有字符串)。如上所述,length將是一個會報告存儲的字符串長度的屬性。

  • 您可以讓結構不公開任何字段,屬性設置器或變異方法,並且有兩個專用字段:一個用於字符串,另一個用於長度,兩者都將設置在構造函數中一個字符串,存儲它,測量它的長度,並存儲它。確定字符串的長度足夠快,以至於計算並緩存它可能是不值得的,但是將字符串和它的GetHashCode值結合起來的結構可能會很有用。

要意識到相對於第三設計,但一個細節是很重要的:如果非線程代碼導致,而另一個線程正在寫入它要讀取的結構的一個實例,可能導致意外創建其字段值不一致的結構實例。由此產生的行爲可能會與以非線程安全方式使用類時發生的行爲有所不同。任何與安全性有關的代碼都必須小心,不要認爲結構字段會處於一致狀態,因爲即使在「完全信任」環境中,惡意代碼也可以輕鬆生成狀態不一致的結構,如果這就是它想要做的。

PS - 如果你希望讓你的結構使用從字符串賦值進行初始化,我會建議使用隱式轉換操作符,使Length是返回底層的長度的只讀屬性如果非null則爲字符串,如果該字符串爲null,則爲零。

+1

雖然你提出了一些有趣的觀點,但實際上並沒有回答這個問題。 – 2014-01-14 09:18:34

+0

我沒有注意到最後的作業 - 只是第一個。爲了考慮後者,你可以定義一個從'String'到你的結構類型的隱式轉換運算符。如果你這樣做,你可能希望'Length'是一個只讀屬性,它只是報告指定字符串字段的長度,如果該字段爲'null',則爲零。 – supercat 2014-01-14 15:57:59

+0

你應該在你的答案中加入。那會把它變成一個實際的答案。一旦你編輯它,我將能夠撤回我的downvote。 – 2014-01-31 13:47:28