Structs should generally represent one of two things:
A single unified entity, such as a fractional number or a moment in time (e.g. a Decimal
or Date
).
A small fixed collection of independent variables stuck together with duct tape, which may sometimes be used individually and sometimes as a group (e.g. the coordinates of a 3d point), and which have no identity beyond the values they contain (so that e.g. any Point3d
with values [1,4,7] is equivalent to any other with those same values).
Microsoft's guidelines are good when applied to things of the first type, but whoever wrote them failed to consider that some useful concepts fit the second pattern much more so than the first. By the sound of things, your data type fits that second pattern. As such, it should have its entire state exposed as public fields (which you do). Further, it should in many cases, when practical, be passed as a ref
parameter. If an exposed-field class is passed as a ref
parameter, the recipient will be able to modify its fields about as easily as it could modify single variables of the corresponding types. Unfortunately, there is no mechanism for exposing properties as ref
parameters. Unless you write your own methods which pass structures as ref
parameters and use those instead of properties, your best bet will probably be to do something like:
var temp = something.myVector;
temp.X += 200;
something.myVector = temp;
an alternative (which could be advantageous if myVector
had many fields) would be to have a method in someThing
like:
delegate void ActByRef<T1>(ref T1 p1);
delegate void ActByRef<T1>(ref T1 p1, ref T2 p2);
void modifyMyVector(ActByRef<myVector> actor)
{
actor(ref _myVector); // _myVector must be manual prop with backing field
}
void modifyMyVector<TX1>(ActByRef<myVector, TX1> actor, ref TX1 px1)
{
actor(ref _myVector, ref px1);
}
A caller that wanted to e.g. add 4 to X
of myVector
could write
something.ModifyMyVector((ref myVector vec) => vec.X+=4;)
If the caller had a vector
called velocity
and it wanted to add a vector perpendicular to that to something.myVector
it could do:
something.ModifyMyVector((ref myVector vec, ref myVector vel) =>
{ vec.X += vel.Y; vec.Y -= vel.X; }, ref velocity);
Note that using ref
parameters with open-field structures can be very efficient, since the time required to pass a struct by ref
is independent of its size. Unfortunately, none of the Framework collections have any such facilities built in, and C# doesn't do much to make such code convenient. Even the approach using the temp
variable is apt to be cleaner and more efficient, however, than code using so-called "immutable" structures or immutable classes.