If you want to pass a struct to a method for the purpose of having that method modify it, the method must use a ref
qualifier on the parameter. If you pass a struct to a method without a ref
parameter, there is no way that the method can modify any fields of that struct.
Note that some people may suggest replacing the struct with a class so that one won't have to use the ref
qualifier. That is a dangerous notion, since every method receiving a reference to a mutable class object will be free to cause the object to be mutated at any time thereafter. There's no clean way to pass a reference to a mutable class object without allowing the recipient to mutate it, nor is there any way to be certain that code which is given a class-object reference won't persist it and use it to modify the object at any arbitrary future time. Structures don't have either of these problems.
If an object holds a value-type field e.g. MyBounds
of type Drawing.Rectangle
, and I call Foo(MyBounds)
I can be assured that there is no possibility that Foo
will change MyBounds
. Further, if I call Bar(ref MyBounds)
I can expect that Bar
might change MyBounds
, but all changes will be complete before the method returns. If Rectangle
had been a mutable class type, then without examining Foo
and Bar
I would have no way of knowing whether the properties of MyBounds
might be changed at any arbitrary time in the future.
Someone who doesn't understand that structs are different from classes may be confused by the way structs behave, but all structs with exposed public fields behave the same way, so if one understands how one such struct works, one will understand them all. There is one evil aspect of structures, which is that instance methods and properties defined on a struct will receive this
as a ref
parameter, but if one attempts to do something like:
readonly System.Drawing.Rectangle myRect = whatever;
...
myRect.Offset(4,2);
the system will recognize that myRect
cannot be passed as a ref
parameter (since it's read-only) and will, without any diagnostic, change the code to:
readonly System.Drawing.Rectangle myRect = whatever;
...
System.Drawing.Rectangle temp = myRect;
temp.Offset(4,2);
What is evil there, however, is not the fact that Rectangle
is mutable, but rather the fact that the compiler assumes the above code substitution is legitimate when calling any and all value-type methods. Unless or until Microsoft gets around to adding an attribute to indicate that calling a particular method on a read-only structure should result in an error rather than performing such substitution, the only safe way to code struct methods that operate on a structure "in-place" would be to use a format like: static void Offset(ref Rectangle it, int x, int y);
, in which case Rectangle.Offset(ref myRect, 4, 2);
would fail as it should.