C# 结构-以尽可能快的速度更改值

C# 结构-以尽可能快的速度更改值,c#,constructor,struct,setter,C#,Constructor,Struct,Setter,假设我有一个X和Y坐标的点结构。 现在我有了构造函数:Point(intx,inty) 问题:我是否也应该添加名为Point.SetXY(intx,inty)的方法 例如: // 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); //

假设我有一个X和Y坐标的点结构。 现在我有了构造函数:Point(intx,inty)

问题:我是否也应该添加名为Point.SetXY(intx,inty)的方法

例如:

// 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?
对于类,我知道它更快,因为您不需要在堆等上创建新实例


但对于结构来说,这可能无关紧要?

除非有很好的理由,否则我建议让结构保持不变——只要在需要时用新的X和Y值创建一个新的结构即可


例如,Eric Lippert在这个问题上的观点是,为什么可变结构可能是违反直觉的(或者(取决于与创造性许可相关的指标)。

我想你可以通过

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

这是最快的

带有暴露字段的结构不是邪恶的。而一些非常旧的编译器会接受以下代码:

List<Point> myList; myList[4].X = 5; 列出我的清单; myList[4].X=5; 它将myList[4]复制到一个临时结构中,修改该临时结构的字段X,然后扔掉修改后的结构,使结构不可变是确保编译器在上述结构中发出嘎嘎声的一种方法,确保编译器对此类代码发出嘎嘎声的更好方法是将编译器更改为禁止写入临时结构的字段。考虑到编译器很长一段时间以来一直禁止使用此类代码,带公开字段的结构通常是保存具有固定数量独立数据项(例如点、矩形等)的对象的最佳方式

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


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

您的基准测试说明什么更快?我还不知道如何使用基准测试。不能一下子学会所有东西。你有理由相信这对你的申请有什么影响吗?这听起来很像过早优化。基准测试=你运行它并记录什么是最快的我知道这是最快的,但我先输入一行代码来设置它。好的,我现在做了测试,两种样式都是相等的,setter样式和构造函数样式的2000000000循环=17秒。您直接访问X和Y的方式=5秒,因此您的答案是最好的。谢谢。@SLaks我想在看到你的评论之前我已经更新了我的答案。@SLaks:为什么它“非常错误”?在任何一种情况下,只要一个好的编译器允许,
someStruct.Field=newValue
的语义与
someStruct=someStruct.WithChangedField(newValue)
应该做的相同,只是前者更快,在多线程场景中,前者的语义比后者的语义规定得更好(例如,直接写入不同字段的线程不会相互干扰,但同时尝试用以不同方式更改的实例替换结构的线程会相互干扰).@SLaks:mutable存储位置中的所有非平凡结构(即那些可以保存任何可与零初始化默认值区分的值的结构)都是可变的。不可变存储位置中的所有结构都是不可变的。此外,如果一个人有一个结构类型的可变存储位置,它允许方便而不是笨拙的变异,那么不管他认为该类型是否应该以这种方式设计,为什么他不应该以设计它的方式对其进行变异呢?我使用这样的结构:我有一个类“Bullet”(示例),在这个类中,我有一个“点位置”;所以我觉得我很安全,因为如果alwyas按类引用这个字段