I have a Struct with a field in it that loses its value. I can declare the field static and that solves the problem. I can also just change struct to class (changing nothing else) and that also solves the problem. I was just wondering why this is?
-
2can you show your code please? – gideon May 13 '12 at 13:07
-
1I think I know what you are trying to do, but post some code. – Tony Hopkinson May 13 '12 at 13:09
-
1I have suspicions to why this is the case, but you need to show your code for that to be confirmed. – Paul Turner May 13 '12 at 13:09
2 Answers
Structs are passed by value. In other words, when you pass a struct, you're passing a copy of its value. So if you take a copy of the value and change it, then the original will appear unchanged. You changed the copy, not the original.
Without seeing your code I cannot be sure, but I figure this is what's happening.
This doesn't happen for classes as they're passed by reference.
It's worth mentioning that this is why structs should be immutable -- that is, that once they're created, they do not change their value. Operations that provide modified versions return new structs.
EDIT: In the comments below, @supercat suggests that mutable properties can be more convenient. However property setters on structs can cause weird failures too. Here's an example that can catch you by surprise unless you deeply understand how structs work. For me, it's reason enough to avoid mutable structs altogether.
Consider the following types:
struct Rectangle {
public double Left { get; set; }
}
class Shape {
public Rectangle Bounds { get; private set; }
}
Ok, now imagine this code:
myShape.Bounds.Left = 100;
Perhaps surprisingly, This has no effect at all! Why? Let's re-write the code in longer yet equivalent form:
var bounds = myShape.Bounds;
bounds.Left = 100;
It's easier to see here how the value of Bounds
is copied to a local variable, and then its value is changed. However at no point is the original value in Shape
updated.
This is pretty compelling evidence to make all public structs immutable. If you know what you're doing, mutable structs can be handy, but personally I only really use them in that form as private nested classes.
As @supercat points out, the alternative is a little unsightly:
myShape.Bounds = new Rectangle(100, myShape.Bounds.Top,
myShape.Bounds.Width, myShape.Bounds.Height);
Sometimes it's more convenient to add helper methods:
myShape.Bounds = myShape.Bounds.WithLeft(100);

- 300,895
- 165
- 679
- 742
-
Struct methods other than property setters which mutate `this` are problematic for the reasons you state. Plain-old-data structs with exposed public fields, however, are often better than structs which only allow updates via constructors. `MyRect.Left += MyRect.Width;` is a lot clearer than `MyRect = new Rectangle(MyRect.Left+MyRect.Width, MyRect.Top, MyRect.Width, MyRect.Height);` and will also execute faster. It's also worth noting that mutable structs can be used in thread-safe fashion while structs that can only be mutated via bulk replacement cannot. – supercat May 14 '12 at 15:34
-
@supercat, I edited my answer with a response that wouldn't fit in a comment. – Drew Noakes May 15 '12 at 13:25
-
Which current compiler accepts `myShape.Bounds.X = 100`? Mine reports "Cannot modify the return value of 'G.Shape.Bounds' because it is not a variable". As for helper methods, they add a large amount of ugly code to the structure definition to do something that could in most cases be handled more quickly and easy via `tempRect = myShape.Bounds; tempRect.X = 100; myShape.Bounds=tempRect;`. – supercat May 16 '12 at 00:05
-
@supercat, I hadn't actually tried to compile that code for a few years. In fact I think it would have been around 2001/2002 when I tried that last, so either the compiler's changed or my memory's duff! If that's the case, then I guess it comes down to style. I still like immutable structs, and they seem to be generally more idiomatic for .NET. This topic has been [covered on SO before many times](http://stackoverflow.com/questions/608542/immutability-of-structs). – Drew Noakes May 16 '12 at 10:22
-
The subject has been covered many times, and countless people say structs should be immutable to prevent broken code like you cited from compiling. I would have regarded that as a valid argument back when compilers would behave as you cite, but the only situation where today's compilers will accept code which futilely mutates temporary copies of read-only storage locations occurs when methods *other than property setters* mutate `this`. Consequently, I regard the notion that structs should wrap their fields in read-only properties as something that was once reasonable advice... – supercat May 16 '12 at 19:58
-
...for solving what was once a problem, but which today simply entails extra work for the creator and consumers of a struct (both the programmers, and the machines running the code) in the interest of solving a problem that no longer exists. Note that I do in general advise against struct methods other than setters modifying `this`, since that can cause silly behaviors that compilers can't warn about. – supercat May 16 '12 at 20:00
-
Example is now a compile error CS1612: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs1612 – SLCH000 Jul 08 '21 at 09:51
When a struct is passed by value, the system will make a copy of the struct for the callee, so it can see its contents, and perhaps modify its own copy, but but cannot affect the fields in the caller's copy. It's also possible to pass structs by ref
, in which case the callee will be able to work with the caller's copy of the struct, modifying it if desired, and even pass it by ref
to other functions which could do likewise. Note that the only way the called function can make the caller's copy of the struct available to other functions, though, is to pass it by ref
, and the called function can't return until all functions to which it has passed the struct by ref
have also returned. Thus, the caller can be assured that any changes which might occur to the structure as a consequence of the function call will have occurred by the time it returns.
This behavior is different from class objects; if a function passes a mutable class object to another function, it has no way of knowing if or when that other function will cause that object to be mutated immediately or at any future time, even after the function has finished running. The only way one can ever be sure that any mutable object won't be mutated by outside code is to be the sole holder of that object from the moment of its creation until its abandonment.
While one who is not used to value semantics may initially be "surprised" at the fact passing a struct by value simply gives the called function a copy of it, and assigning one struct storage location to another simply copies the contents of the struct, the guarantees that value types offer can be very useful. Since Point
is a structure, one can know that a statement like MyPoints[5].X += 1;
(assuming MyPoints
is an array) will affect MyPoints[5].X
but will not affect any other Point
. One can further be assured that the only way MyPoints[5].X
will change is if either MyPoints
gets replaced with another array, or something writes to MyPoints[5]
. By contrast, Point
were a class and MyPoint[5]
had ever been exposed to the outside world, the only way of knowing whether the aforementioned statement would affect field/property X
of any other storage locations of type Point
would be to examine every single storage location of type Point
or Object
that existed anywhere within the code to see if it pointed to the same instance as MyPoints[5]
. Since there's no way for code to examine all of the storage locations of a particular type, such assurance would be impossible if Point[5]
had ever been exposed to the outside world.
There is one annoying wrinkle with structs, though: generally, the system will only allow structures to be passed by ref
if the called code is allowed to write to the structure in question. Struct method calls and property getters, however, receive this
as a ref
parameter but do not have the above restriction. Instead, when invoking a struct method or property getter on a read-only structure, the system will make a copy of the structure, pass that copy by ref
to the method or property getter, and then discard it. Since the system has no way of knowing whether a method or property getter will try to mutate this
, it won't complain in such cases--it will just generate silly code. If one avoids mutating this
in anything other than property setters (the system won't allow the use of property setters on read-only structures), however, one can avoid problems.

- 77,689
- 9
- 166
- 211