的Structs暴露字段是不是邪恶。虽然一些非常老的编译器会接受类似的代码:
List<Point> myList;
myList[4].X = 5;
这将复制myList中[4]为临时结构,修改临时结构领域X,然后抛出修改后的结构远,使得结构不变是一种确保编译器能够对上述构造进行攻击的方法,确保编译器在这些代码中发声的更好方法是将编译器更改为禁止写入临时结构的字段。由于这些代码长时间被编译器禁止,因此暴露域的结构通常是保存具有固定数量的独立数据项(例如Point,Rectangle等)的东西的最佳方式。
什么是问题是构造函数或属性设定器以外的函数修改this
的结构。虽然编译器会认识到写入someStructProperty.someField
正在尝试修改someStructProperty
,并且在这种修改实际上不起作用的情况下将禁止它,但不幸的是,编译器不知道someStructProperty.MutatingFunction()
会尝试修改临时实例结构。因此编译器会允许这样的代码,尽管它实际上不能按预期工作。如果函数应该修改一个结构“in place”,我会建议作为一种补救措施,那就是定义一个静态方法,它将结构的一个实例作为参数ref
。例如,SetPointXY(ref Point pt, int x, int y)
。编译器会将结构的传递视为ref
参数作为修改该结构的尝试,并且只会在实际工作的情况下允许它。
请注意,从性能的角度来看,只有单独编写struct字段不会是更新结构的最快方法,那就是当大部分结构匹配默认值或其他预设值时,现有的结构。可能有一些情况下,用一个预先存在的实例覆盖一个结构会更快,然后编写应该包含不同内容的字段,但通常我会建议应该使用方法或函数来仅在更新结构时才会更新结构这样做的代码比单独设置字段的代码更具可读性。如果AreaCode
是PhoneNumber
类型的公共字段,则somePhoneNumber.AreaCode = "847";
的效果远远超过somePhoneNumber = new PhoneNumber("847", somePhoneNumber.Exchange, somePhoneNumber.Number, somePhoneNumber.Extension);
的效果。除其他外,必须研究整个结构以了解后者是否会改变AreaCode
以外的任何字段。另一方面,如果一个人的目标实际上是一个空白的结构,除了一些全新的数据,那么使用构造函数或工厂方法可能有助于澄清这样一个事实:如果单独覆盖结构的所有字段,则必须研究整个结构以知道没有任何字段可以保持不变。
你的基准测试表明速度更快? – 2012-02-21 16:01:51
我不知道如何使用基准。无法一次学习所有内容。 – zgnilec 2012-02-21 16:02:59
您是否有理由相信它在您的应用程序中有所不同?这听起来像是过早的优化。 – 2012-02-21 16:04:09