2

I have a struct in C# defined as follows(simplified for demonstration purposes), which I use in interop calls to a native 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");
    }
}

Update: This struct is a property within another class. As follows:

public class MyClass
{
    MyStruct MyStruct { get; set; }
}

When I instantiate the struct with a value and follow this by a call to Clear(), the contents are not cleared. When I step into the Clear() method with the debugger I see each field getting cleared. Yet, once the call to Clear() completes, the original struct instance remains unaltered with its originally instantiated values.

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());

The above results in the following output:

Init: 1234-5678
Clear: 1234-5678

Why is this? Can one clear a struct after it has been instantiated?

Edit: Sample code and results can be seen here: http://ideone.com/6szn9

Edit: Revised question to more accurately reflect the problem being related to the property accessor.

Elan
  • 6,084
  • 12
  • 64
  • 84
  • possible duplicate of [Problem with struct and property in c#](http://stackoverflow.com/questions/3729873/problem-with-struct-and-property-in-c-sharp) – dthorpe Apr 11 '12 at 16:07

2 Answers2

5

Doesn't do that for me. http://ideone.com/PDLnt

Does your real code use a property by any chance? A property getter makes a copy when it returns.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 2
    I agree with Ben, I suspect what is actually happening is a copy of your struct instance is getting made at some point. It's a common pitfall with structs in C# – Matt Greer Mar 25 '11 at 04:36
  • Yes, indeed my struct is a property within another class. I updated the code to show this. Is the property accessor to the struct the problem? – Elan Mar 25 '11 at 04:47
  • Your code still includes `struct1` which isn't accounted for in the code you've provided. But since it's a property on a class, then there's a good chance you are making copies of the struct without realizing it. Every time you call the getter on that property, a copy of the struct is returned. Just like if it was an `int` or some other primitive type. – Matt Greer Mar 25 '11 at 04:49
  • Corrected the code, ran it and the results can be seen here: http://ideone.com/6szn9. Thanks for the clarification on copies being made on the property. BTW, I wasn't aware of http://ideone.com. Pretty cool! – Elan Mar 25 '11 at 04:56
  • 1
    Yup, every call to `class1.MyStruct` is returning a fresh copy of the struct. If you do this instead `MyStruct s = class1.MyStruct; Console.WriteLine(s.ToString()); s.Clear(); Console.WriteLine(s.ToString());` you should see the behavior you want. – Matt Greer Mar 25 '11 at 05:00
  • I get it. I guess, I might have liked slightly different behavior where the Clear() call got applied prior to the copy or got applied to the copy itself. Oh well... I get it and know what to do now. Thanks! – Elan Mar 25 '11 at 05:10
  • @Elan: Of course, the `Clear` implementation is quite unnecessary, you can just say `class1.MyStruct = default(MyStruct);` in order to zero out all fields. – Ben Voigt Mar 25 '11 at 05:15
  • @Ben: Yes, I get it. I can of course also do class1.MyStruct = new MyStruct(). My earlier thought trail was to reuse the already instantiated object, but I see it is different here when dealing with structs. Thanks for helping me resolve this. – Elan Mar 25 '11 at 05:53
  • Understanding the difference between value types and reference types is a pivotal moment in any C# coders career... welcome to level 2 ;) – MattDavey Mar 25 '11 at 14:10
0

What you are seeing is a significant limitation in the way properties work. If you want to modify a struct that's only accessible as a property and not as a field, you will have to read the struct into a temporary variable, modify it, and store it back. Some would claim this as an argument against mutable structs. I would argue that while the limitation is unfortunate, code like:

  Rectangle tempRect = thing.Bounds;
  tempRect.X += 10;
  thing.Bounds = tempRect;

is clearer and more self-explanatory than it would be if Rectangle were anything other than a mutable struct.

supercat
  • 77,689
  • 9
  • 166
  • 211