可变结构有什么好处?
所以我知道可变结构/值类型在 .Net 中被认为是“邪恶的”。那么为什么可以制造它们呢?可变结构有哪些好的用途可以证明首先将该功能添加到 CLR 是合理的?
So I know that mutable structs/value types are considered 'evil' in .Net. So why is it possible to make them? What are some good uses for mutable structs that justify adding the feature to the CLR in the fist place?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一个很好的问题!就我个人而言,我绝对不是一个粉丝,但是有些在 CF/XNA 等上运行的人会盲目地发誓他们需要通过(过度)使用结构来获得额外的性能,这通常涉及它们是可变的。如果直接在数组、公共字段上访问该结构,或者通过 ref 访问该结构,则此参数具有 some 值,但在许多情况下,您可能会因咀嚼而被咬住通过在堆栈上多次复制过大的结构来节省堆栈空间。
如果您正在使用结构,无论是否可变,并且如果您正在使用序列化,那么完全不可变的结构可能是一个真正的问题。部分或“冰棒”不变性可以是这里的一个答案,但是对值类型有吸引力的相同框架也往往有更多的反射限制,使得私有/基于字段的序列化变得棘手。所以可变很方便。
上述所有内容实际上都是使用结构体来保存实际上更好地归类为对象的东西的示例。 纯值不会改变。曾经。所以完全不变性就可以了。
作为最后的想法……不是存在的理由,但它是极好的采访素材,并且非常适合绊倒粗心的人。也许它是由充当顾问的人设计的;p
An excellent question! Personally, I'm definitely not a fan, however some people running on things like CF/XNA will swear blind that they need the extra bit of performance they can eek from (over)using structs, which generally involves them being mutable. This argument has some value if the struct is accessed directly in an array, on a public field, or accessed via
ref
, but in many cases you might get bitten by chomping through stack-space by duplicating an over-sized struct many times on the stack.If you are using structs, mutable-or-not, and if you are using serialization, then a fully immutable struct can be a real problem. Partial or "popsicle" immutability can be an answer here, but the same frameworks that are tempting for value-types also tend to have more reflection restrictions, making private/field-based serialization tricky. So mutable is handy.
All of the above are really examples of using a struct to hold something that is actually better classified as an object. Pure values don't change. Ever. So full immutability is fine.
As a final thought... not a justification for the existence, but it makes excellent interview fodder, and is great for tripping up the unwary. Maybe it was designed by people acting as consultants ;p
部分可变的结构非常适合为这些结构创建构建器。
因此,如果您有类似的情况:
在一个程序集中,然后该程序集之外的任何内容都无法修改您构建的结构,但构建它们很容易。
Partially mutable structs are good for making builders for those structs.
So if you have something like:
In one assembly, and then anything outside that assembly cannot modify the struct you build, but building them is easy.
可变结构是 .net 中唯一可以实现可变值语义的数据类型。像 Eric Lippert 这样的一些人讨厌它们,因为它们让编译器编写者的生活变得更加复杂,但它们提供的语义通常比引用类型提供的语义清晰得多。
例如,假设有一个类和一个结构类型以及一个接口,如下所示:
并考虑以下方法:
假设 munger 不使用任何不安全代码,则哪些传入项可能有其
。 v
字段受四个语句中哪一个的影响?我建议,即使没有看到 struct1 的整个定义,或者 munger 实现的任何部分,人们也可以知道 struct1.v 不会被它们中的任何一个改变。有保证。此外,struct2.v 可以由 S2 更改,但不能由任何其他语句更改。再次保证。然而,class1.v 和 class2.v 的值可以通过任何语句更改;了解哪些语句可以更改 class1.v 或 class2.v 的唯一方法是检查现在或将来将实现 ISample 的每种类型的代码。换句话说,结构提供有限但定义良好的语义。课程没有。
顺便说一句,由于属性工作方式的限制,人们不能直接修改结构体属性的字段,也不能通过引用传递结构体属性的字段。即便如此,像这样的代码
虽然不是线程安全的,但具有清晰可见的语义。用 myClass 替换 myStruct,确定性就消失了。如果列表中的每一项都有一个非共享的 myClass 实例,则可以简单地说
myList[1].v = 5;
,既美观又方便。不幸的是,确定列表项是否具有 myClass 的非共享实例几乎是不可能的。如果有人试图将myList[1]
中的值复制到myList[0]
时说过类似myList[0] = myList[1];< /code>,这样的语句会起作用,但会导致对
myList[1].v
的后续写入也会影响myList[0].v
。讨厌讨厌讨厌。结构不会有这个问题。Mutable structs are the only kind of data type in .net which can implement mutable value semantics. Some people like Eric Lippert hate them because they make life more complicated for compiler writers, but the semantics they offer are frequently much clearer than those available with reference types.
For example, suppose one has as class and a struct type, and an interface as follows:
and consider the following method:
Assuming only that munger does not use any unsafe code, which of the passed-in items may have their
.v
field affected by which of the four statements? I would suggest that even without seeing the entire definition of struct1, or any portion of the implementation of munger, one can tell that struct1.v will not be changed by any of them. Guaranteed. Further, struct2.v may be changed by S2, but not by any of the other statements. Again, guaranteed. The values of class1.v and class2.v, however, may be changed by any of the statements; the only way to know which of the statements could change class1.v or class2.v would be to examine the code for every single type that will ever, now or in the future, implement ISample.In other words, structs offer semantics that are limited but well-defined. Classes don't.
Incidentally, because of limitations in how properties work, one cannot directly modify, nor pass by reference, fields of struct properties. Even so, code like:
while not thread-safe, has clear and obvious semantics. Substitute myClass for myStruct, and certainty goes out the window. If each item of the list has an unshared instance of myClass, one could simply say
myList[1].v = 5;
, nicely and conveniently. Unfortunately, determining whether a list item has an unshared instance of myClass is almost impossible. If someone, trying to copy the values inmyList[1]
tomyList[0]
had said something likemyList[0] = myList[1];
, such a statement would have worked, but would cause a subsequent write tomyList[1].v
to also affectmyList[0].v
. Nasty nasty nasty. Structs wouldn't have that problem.