2010-09-16 125 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