简体   繁体   中英

Another “Why shouldn't structs be mutable?” C#

I've read When should I use a struct instead of a class? which references MSDN's guidance, which says:

Do not define a structure unless the type has all of the following characteristics:

  • It logically represents a single value, similar to primitive types (integer, double, and so on).
  • It has an instance size smaller than 16 bytes.
  • It is immutable.
  • It will not have to be boxed frequently.

and Why are mutable structs “evil”? has answer:

Structs are value types which means they are copied when they are passed around.

I'm struggling to understand why I shouldn't just be conscious that structs need to be passed by reference, else changes made to the version passed through a function will not affect the original. Yes, I've had tons of bugs from this in the past, but now I'm experienced enough that I'm careful not to have it happen.

I make exclusively games in C#, and variables for stuff in games need to change a lot.

Say I have a player character, represented by class "Player" in my game. If Player has variables X and Y to say where it is, these would change a lot. I wouldn't want to create a new Player every time it moves, just to preserve immutability? So my class should be mutable. OK.

But what if I want to store data about my entity. If I store its position on the screen in a Rectangle (x,y,w,h), should I make Rectangle a CLASS because it's going to be mutable? It's just a logical collection of 4 variables, so a struct seems sensible as a container to me.

I also have "Colour" as a struct (r,g,b,a), but I have it as mutable because I might want to shift the alpha of things in the game to fade them in/out, or colour something red for a second when it gets hurt, without the overhead of calling "new Colour" every render call.

I saw another post which said structs should be used if these conditions are met:

  • Is the main responsibility of the type data storage?
  • Is its public interface defined entirely by properties that access or modify its data members?
  • Are you sure your type will never have subclasses?
  • Are you sure your type will never be treated polymorphically?

The answer to this would be "yes" for the structs I use, but most of them would be mutable.

I'm confused about all of the conflicting advice here. Are mutable structs OK for certain types of use, or am I designing my code all wrong?

It's not just the chance of accidentally losing information:

list.ForEach(item => item.X = 10);
// this code does nothing useful if item is a mutable struct

It's also the weird interaction between mutating methods and readonly :

readonly MutableStruct m_field;
...
m_field.MutatingMethod(); // mutates a temporary copy rather than the field

But if you've determined through profiling that:

  • You cannot afford reference types, because, say, GC pressure, or you want to put all your objects in an array for better locality
  • You cannot afford to copy the entire struct when you modify it
  • You cannot reasonably change your design to work around these issues (make the structs smaller, have a pool of reference type objects, etc.)
  • You know what you're doing

Then mutable structs may be what you need. That's why they're in the language after all.

Speaking of game code, SharpDX is full of mutable structs ( example ) and methods that pass by reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM