2010-09-16 53 views
27

在一個文件中我定義了一個公共結構問題的結構和性能在C#

public struct mystruct 
{ 
    public Double struct1; 
    public Decimal struct2; 
} 

在另一個我試圖做到這一點:

class Test 
{ 
    mystruct my_va; 

    public mystruct my_va 
    { 
     get { return my_va; } 
     set { my_va = value; } 
    } 

    public Test() 
    { 
     my_va.struct1 = 10; 
    } 
} 

智能感知識別My_va.struct1但是編譯器說

錯誤1不能修改返回值的「TEST.mystruct」 ,因爲它不是一個 變量

如何更正語法?

回答

32

強烈建議,以避免可變的結構。他們展示各種令人驚訝的行爲。

解決方案:使您的結構不可變。

public struct MyStruct 
{ 
    public readonly double Value1; 
    public readonly decimal Value2; 

    public MyStruct(double value1, decimal value2) 
    { 
     this.Value1 = value1; 
     this.Value2 = value2; 
    } 
} 

用法:

class Test 
{ 
    private MyStruct myStruct; 

    public Test() 
    { 
     myStruct = new MyStruct(10, 42); 
    } 

    public MyStruct MyStruct 
    { 
     get { return myStruct; } 
     set { myStruct = value; } 
    } 
} 
+1

@Caspar Kleijne:Value1和Value2是字段,而不是自動屬性。所以不行。 – dtb 2010-09-16 19:13:51

+1

對,對不起....公共領域是醜陋的.... – 2010-09-16 19:16:28

+1

謝謝你的作品,但你能解釋爲什麼你的語法工作,而不是我的,我真的不明白的根本區別:爲什麼通過使它只讀有什麼做設置屬性值? – user310291 2010-09-16 19:28:27

47

是的,這是絕對正確的。你看,當你My_va,你正在提取一個值 - 當前值my_va的副本。更改該值不會有好處,因爲您會立即丟棄該副本。編譯器阻止你編寫代碼,它看起來並不像它那樣做。

通常,避免可變結構。他們是邪惡的。在這種情況下,您可以(例如)改變mystruct爲不可變的,但這樣的方法:

public mystruct WithStruct1(double newValue) 
{ 
    return new mystruct(newValue, struct2); 
} 

然後改變你的構造函數代碼:

My_va = My_va.WithStruct1(10); 

...雖然在這種情況下,它更可能(因爲你在一個構造函數是),你應該寫:

My_va = new mystruct(10, 0); 

不僅要結構b e不變的,在大多數代碼庫中,IMO應該是非常罕見的。除了Noda Time之外,我幾乎沒有寫過自己的自定義值類型。

最後,請了解.NET naming conventions並嘗試跟隨他們,甚至示例代碼:)

+26

我曾經聽說過燒燬整個村莊的可變結構的故事。 Twas瘋狂。 – 2010-09-16 19:09:57

+22

@Anthony:你「曾經聽過一個故事」?你讓它聽起來像你不相信。我在那裏,看到了一切。它仍然在夜間困擾着我。 – 2010-09-16 19:12:09

+8

阿納金天行者很酷,直到他了解到可變結構。 – Josh 2010-09-16 19:13:48

3

簡單的解決辦法:結構更改爲類。

2

我使用了一個結構體列表,並以不同的方式解決了這個問題。

struct Pixel 
{ Public int X; 
    Public int C; 
} 
List<Pixel> PixelList = new List<Pixel> 
TempPixel = new Pixel(); 

現在,當我想設置一個值,我這樣的代碼:

TempPixel = PixelList[i]; 
TempPixel.X= 23; // set some value 
PixelList[i] = TempPixel 

代碼看起來有點怪也許,但它解決了問題。 它解決了結構不能直接分配單個值的問題,但可以是類似類型的副本。 解決錯誤CS1612:

https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28CS1612%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV2.0%22%29;k%28DevLang-CSHARP%29&rd=true

+1

代碼看起來並不奇怪。相反,如果一個人不能或不願意使用一系列結構,這是正確的方法。有些人不喜歡可變結構,因爲它們的行爲不像對象,但是在需要用膠帶粘在一起的變量的情況下,我認爲最好使用一堆粘在膠帶上的變量,而不是嘗試使一個結構表現得像一個平庸的模仿一個對象,這個對象模仿一堆粘在膠帶上的變量。我會注意到的一件事... – supercat 2015-03-10 14:49:19

+0

...是用'Pixel [] Pixels = new Pixel [16]'替換'List PixelList'可能更方便更高效。/*或者一些合理的默認值*/int PixelCount;',並添加'void AddPixel(Pixel newPixel){if(PixelCount> = Pixels.Count)Pixels = Array.Resize(ref Pixels,PixelCount * 2);像素[PixelCount] = newPixel; PixelCount ++; }'。這樣做將允許數組元素就地更新。 – supercat 2015-03-10 14:54:11

+0

你的權利,我用它在一些'危險的'多線程代碼,作爲一個全局變量列表。我走出了危險區域,因爲我的代碼使用結構運行得非常快。我不認爲結構應該使用很多,但在奇怪的情況下,我會在專用硬件上使用pointcloud數據做一些奇怪的事情,那麼它可能會更好;在使用結構之前,我建議人們看看他們是否真的需要它。速度和低內存消耗,可能是原因。 – user613326 2015-03-10 16:38:24

1

不幸的是可以分配給一個屬性時(即調用屬性setter)被不正確地生成此錯誤。一個不可變的結構體仍然可以擁有一個有效的屬性設置器,只要該屬性設置器沒有實際分配給結構體中的任何字段即可。例如,

public struct Relay 
{ 
    public Relay(Func<string> getText, Action<string> setText) 
    { 
     this.GetText = getText; 
     this.SetText = setText; 
    } 
    private readonly Func<string> GetText; 
    private readonly Action<string> SetText; 

    public string Text { 
     get { return this.GetText(); } 
     set { this.SetText(value); } 
    } 
} 

class Example 
{ 
    private Relay Relay { 
     get { return new Relay(() => this.text, t => { this.text = t; }); } 
    } 

    private string text; 


    public Method() 
    { 
     var r = new Relay(); 
     r.Text = "hello"; // not a compile error (although there is a null reference) 

     // Inappropriately generates a compiler error 
     this.Relay.Text = "hello"; 

     r = this.Relay; 
     r.Text = "hello"; // OK 
    } 
} 
+0

「錯誤」CS 1612應該是一個警告。 我怎樣才能回饋給微軟,使它得到解決? 我不想使用一個類,因爲顯然,這涉及到開銷,這在我的情況下是不合適的。 – 2017-03-11 02:52:51