简体   繁体   English

另一个“为什么结构不可变?”C#

[英]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: 参考MSDN的指导,其中说:

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. 它的实例大小小于16个字节。
  • 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. 我只使用C#制作游戏,游戏内容的变量需要改变很多。

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. 如果玩家有变量X和Y来说明它的位置,那么这些变化会很大。 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? 如果我在Rectangle(x,y,w,h)中将其位置存储在屏幕上,我是否应该将Rectangle设为CLASS,因为它是可变的? It's just a logical collection of 4 variables, so a struct seems sensible as a container to me. 它只是4个变量的逻辑集合,因此结构对我来说似乎是合理的容器。

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. 我也有“颜色”作为一个结构(r,g,b,a),但我有它可变,因为我可能想要改变游戏中的东西的α来淡入/淡出它们,或者将颜色变为红色一秒钟受到伤害,没有每次渲染调用调用“new Color”的开销。

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之间奇怪的相互作用

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 您无法负担参考类型,因为,例如,GC压力,或者您希望将所有对象放在数组中以获得更好的局部性
  • 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. 说到游戏代码,SharpDX充满了可变结构( 示例 )和通过引用传递的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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