为啥我不能更改实例化后用作属性的结构中的字段?

Posted

技术标签:

【中文标题】为啥我不能更改实例化后用作属性的结构中的字段?【英文标题】:Why can I not alter fields in a struct that is used as a property after instantiation?为什么我不能更改实例化后用作属性的结构中的字段? 【发布时间】:2011-03-25 04:24:29 【问题描述】:

我在 C# 中定义了一个结构如下(为演示目的而简化),我在对本机 DLL 的互操作调用中使用它:

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct MyStruct

    private byte val0;
    private byte val1;
    private byte val2;
    private byte val3;

    public MyStruct(UInt32 id)
    
        this.val0 = (byte)id;
        id >>= 8;
        this.val1 = (byte)id;
        id >>= 8;
        this.val2 = (byte)id;
        id >>= 8;
        this.val3 = (byte)id;
    

    public void Clear()
    
        this.val0 = this.val1 = this.val2 = this.val3 = 0;
    

    public override string ToString()
    
        return
            this.val3.ToString("X2") + this.val2.ToString("X2") + "-" +
            this.val1.ToString("X2") + this.val0.ToString("X2");
    

更新: 该结构是另一个类中的属性。如下:

public class MyClass

    MyStruct MyStruct  get; set; 

当我用一个值实例化结构并随后调用 Clear() 时,内容不会被清除。当我使用调试器进入 Clear() 方法时,我看到每个字段都被清除了。然而,一旦对 Clear() 的调用完成,原始结构实例将保持其原始实例化值不变。

MyClass class1 = new MyClass();
class1.MyStruct = new MyStruct(0x12345678);
System.Diagnostics.Debug.WriteLine("Init: " + class1.MyStruct.ToString());
class1.MyStruct.Clear();
System.Diagnostics.Debug.WriteLine("Clear: " + class1.MyStruct.ToString());

以上结果如下:

初始化:1234-5678 清除:1234-5678

这是为什么?实例化后可以清除结构吗?

编辑: 示例代码和结果可以在这里看到:http://ideone.com/6szn9

编辑:修改问题以更准确地反映与属性访问器相关的问题。

【问题讨论】:

Problem with struct and property in c#的可能重复 【参考方案1】:

不适合我。 http://ideone.com/PDLnt

您的真实代码是否会使用属性?属性 getter 在返回时会进行复制。

【讨论】:

我同意 Ben 的观点,我怀疑实际发生的事情是您的 struct 实例的副本正在某个时候生成。这是 C# 中结构的常见缺陷 是的,确实我的结构是另一个类中的属性。我更新了代码以显示这一点。结构的属性访问器是问题吗? 您的代码仍然包含struct1,这在您提供的代码中没有说明。但是由于它是类的一个属性,那么您很有可能在没有意识到的情况下复制了该结构。每次调用该属性的 getter 时,都会返回该结构的副本。就像它是 int 或其他一些原始类型一样。 更正了代码,运行它,结果可以在这里看到:ideone.com/6szn9。感谢您对在该物业上制作的副本进行澄清。顺便说一句,我不知道ideone.com。很酷! 是的,每次调用class1.MyStruct 都会返回一个新的结构副本。如果你改为这样做MyStruct s = class1.MyStruct; Console.WriteLine(s.ToString()); s.Clear(); Console.WriteLine(s.ToString());,你应该会看到你想要的行为。【参考方案2】:

您看到的是属性工作方式的一个重大限制。如果要修改只能作为属性而不是字段访问的结构,则必须将该结构读入临时变量,对其进行修改,然后将其存储回来。有些人会声称这是反对可变结构的论据。我会争辩说,虽然限制是不幸的,但代码如下:

矩形 tempRect = thing.Bounds; tempRect.X += 10; thing.Bounds = tempRect;

如果 Rectangle 不是一个可变结构,它会更清晰、更不言自明。

【讨论】:

以上是关于为啥我不能更改实例化后用作属性的结构中的字段?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能从 VBA 中的多实例表单中获取当前记录 ID

模式实例化后如何使猫鼬模式属性唯一(已包含数据)

Swift iOS - 我为啥可以循环遍历一组类对象并进行属性更改但不能更改结构[重复]

无法在 main() 方法中实例化字段(实例变量)。为啥??爪哇

为啥我不能将泛型类型的一个实例转换为另一个实例?

在 C 中是不是有一个函数可以用作“实例方法”?