结构-尽可能快地更改值

本文关键字:尽可能 结构 | 更新日期: 2023-09-27 18:25:31

想象一下,我有一个X和Y坐标的Point结构。现在我有了构造函数:Point(int x,int y)。

问题:我还应该添加名为Point.SetXY(int x,int y)的方法吗?

示例:

// I have some point
point = new Point (5,5);
// and I wanna change some values
point = new Point (7,7);
// or maybe should I do like this?
point.SetXY (7,7); // is it faster?

对于类,我知道它更快,因为你不需要在堆等上创建新的实例。

但也许对structs来说,这无关紧要?

结构-尽可能快地更改值

除非有充分的理由,否则我建议您的结构不可变-只需在需要时创建一个具有新X和Y值的新结构即可。

例如,为什么可变结构可能是反直觉的(或邪恶的(取决于与创造性许可相关的指标)),Eric Lippert有一篇关于这个主题的非常好的博客文章。

我认为你可以通过实现

point.X = 7;
point.Y = 7;

这是最快的

具有公开字段的结构不是邪恶的。而一些真正古老的编译器会接受以下代码:

列表<要点>myList;myList[4].X=5;

它会将myList[4]复制到一个临时结构,修改该临时结构的字段X,然后将修改后的结构丢弃,而使结构不可变是确保编译器对上述结构发出嘎嘎声的一种方法,确保编译器对此类代码发出嘎嘎声更好的方法是将编译器更改为禁止写入临时结构的域。考虑到编译器长期以来禁止使用此类代码,具有公开字段的结构通常是保存具有固定数量独立数据项(如点、矩形等)的东西的最佳方式。

有问题的是构造函数或属性设置器以外的函数修改this的结构。虽然编译器会意识到对someStructProperty.someField的写入试图修改someStructProperty,并且在这种修改实际上不起作用的情况下会禁止它,但不幸的是,编译器无法知道someStructProperty.MutatingFunction()会试图修改结构的临时实例。因此,编译器将允许这样的代码,即使它实际上不能按预期工作。在函数应该"就地"修改结构的情况下,我建议定义一个静态方法,将结构的实例作为ref参数。例如,SetPointXY(ref Point pt, int x, int y)。编译器会将结构作为ref参数的传递视为修改该结构的尝试,并且只允许在实际工作的情况下进行。

请注意,从性能的角度来看,只有在使结构的大部分与默认值或其他预先存在的结构匹配时,单独写入结构字段才不是更新结构的最快方式。在某些情况下,用预先存在的实例覆盖结构,然后编写应该包含不同内容的字段会更快,但总的来说,我建议只有当这样做的代码比单独设置字段的代码更可读时,才应该使用方法或函数来更新结构。如果AreaCodePhoneNumber类型的公共字段,则somePhoneNumber.AreaCode = "847";的效果远比somePhoneNumber = new PhoneNumber("847", somePhoneNumber.Exchange, somePhoneNumber.Number, somePhoneNumber.Extension);的效果清晰。除其他外,必须研究整个结构,才能知道后者是否会改变AreaCode以外的任何字段。另一方面,如果一个人的目标实际上是拥有一个除了一些全新数据之外都是空白的结构,那么使用构造函数或工厂方法可能有助于明确这样做的事实;如果简单地单独覆盖结构的所有字段,则必须研究整个结构才能知道没有任何字段保持不变。