2012-02-21 92 views
-1

想象一下,我有一个带有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? 

,因为我知道这是更快,因为ü不类需要在堆等

但也许对于结构,它不创造物质新的实例?

+1

你的基准测试表明速度更快? – 2012-02-21 16:01:51

+0

我不知道如何使用基准。无法一次学习所有内容。 – zgnilec 2012-02-21 16:02:59

+1

您是否有理由相信它在您的应用程序中有所不同?这听起来像是过早的优化。 – 2012-02-21 16:04:09

回答

2

我思,你可以通过

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

实现呢?这是最快的

+0

但这是非常错误的。 – SLaks 2012-02-21 16:06:50

+0

我知道这是最快的,但我优先考虑1行代码来设置它。 – zgnilec 2012-02-21 16:13:56

+0

好的,我现在做了测试,两种样式都是等于,设置器样式和构造器样式为2000,000,000循环= 17秒。你的风格直接访问X和Y = 5秒,所以你的答案是最好的。谢谢。 – zgnilec 2012-02-21 16:36:09

4

除非有很好的理由,否则我会建议让你的结构体不可变 - 只需在需要时用新的X和Y值创建一个新的结构体。

有关可变结构可能违反直觉的示例(或evil(取决于与创意许可有关的度量标准))Eric Lippert对此主题有a very good blog post

+0

我正在使用这样的结构:我有一个类'Bullet'(示例),并且在这个类中我有一个'Point position';所以我认为我很安全,因为如果alwyas按照课程反对这个领域。 – zgnilec 2012-02-21 16:16:42

+0

该博客帖子涉及其方法变异“this”的结构,这确实有问题。有些人似乎认为'这个'变异的结构是有问题的,或者一些非常早期的编译器可能会在结构暴露出字段时生成愚蠢的代码,这是一般的可变结构的一个论据,但我只是没有看到它。 – supercat 2012-02-22 20:08:57

1

的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字段不会是更新结构的最快方法,那就是当大部分结构匹配默认值或其他预设值时,现有的结构。可能有一些情况下,用一个预先存在的实例覆盖一个结构会更快,然后编写应该包含不同内容的字段,但通常我会建议应该使用方法或函数来仅在更新结构时才会更新结构这样做的代码比单独设置字段的代码更具可读性。如果AreaCodePhoneNumber类型的公共字段,则somePhoneNumber.AreaCode = "847";的效果远远超过somePhoneNumber = new PhoneNumber("847", somePhoneNumber.Exchange, somePhoneNumber.Number, somePhoneNumber.Extension);的效果。除其他外,必须研究整个结构以了解后者是否会改变AreaCode以外的任何字段。另一方面,如果一个人的目标实际上是一个空白的结构,除了一些全新的数据,那么使用构造函数或工厂方法可能有助于澄清这样一个事实:如果单独覆盖结构的所有字段,则必须研究整个结构以知道没有任何字段可以保持不变。