gpt4 book ai didi

c# - 如何在 foreach 循环中修改结构的属性?

转载 作者:太空宇宙 更新时间:2023-11-03 22:45:19 24 4
gpt4 key购买 nike

我希望下面的代码能够工作:

foreach (Rect item in VM.Cubes)
{
VM.FallDown(ref item);
}

class VM
{
public void FallDown(ref Rect entity)
{
if ((entity.Y + entity.Height < 800))
{
entity.Y++;
}
}
}

由于 Rect 是一个结构体,它是一个值类型,如果我在调用该方法时通过引用传递参数,我只能更改它的 Y 属性。不幸的是,foreach 不喜欢在遍历它们时更改它的元素,但由于 VM.Cubes 也是一个列表,我也不能使用常规的 for 循环。

我应该怎么做才能让它发挥作用?

最佳答案

我想我可以在这里插话......

虽然我同意不可变结构在很多情况下都有意义,但可读性和维护性也应该始终成为您考虑的因素。如果性能是您的目标,那么在 Linq Select 中创建一个新结构不会叠加(在这种情况下)。您只是在执行更多分配并产生更多垃圾。

在任何正常情况下,这可能都无关紧要。但是,“如果”您对性能感兴趣并且您有指令和周期OCD,那么我会考虑替代方案并对您的解决方案进行基准测试。

给出以下3种方法

public void ByRef(ref Rect entity)
{
if (entity.Y + entity.Height > 800)
{
entity.Y++;
}
}

public Rect ByImutableReturn(Rect entity)
{
return entity.Y + entity.Height > 800 ? new Rect(entity.Height, entity.Y + 1) : entity;
}

public Rect ByReturn(Rect entity)
{
if (entity.Y + entity.Height > 800)
{
entity.Y++;
}

return entity;
}

LinqImutableReturn

protected override List<Rect> InternalRun()
{
return Input.Cubes = Input.Cubes.Select(r => Input.ByImutableReturn(r))
.ToList();
}

LinqReturn

protected override List<Rect> InternalRun()
{
return Input.Cubes = Input.Cubes.Select(r => Input.ByReturn(r))
.ToList();
}

ForLoopByRef

protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
var t = Input.Cubes[index];
Input.ByRef(ref t);
Input.Cubes[index] = t;
}

return Input.Cubes.ToList();
}

ForLoopImutableReturn

protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
Input.Cubes[index] = Input.ByImutableReturn(Input.Cubes[index]);
}

return Input.Cubes.ToList();
}

ForLoopReturn

protected override List<Rect> InternalRun()
{
for (var index = 0; index < Input.Cubes.Count; index++)
{
Input.Cubes[index] = Input.ByReturn(Input.Cubes[index]);
}

return Input.Cubes.ToList();
}

结果

Mode            : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 100 times (averaged/scale)

Scale : 10,000
Name | Time | Range | StdDev | Cycles
--------------------------------------------------------------------------
ForLoopByRef | 0.073 ms | 0.001 ms | 0.07 | 244,964
ForLoopReturn | 0.097 ms | 0.006 ms | 0.05 | 332,372
ForLoopImutableReturn | 0.116 ms | 0.003 ms | 0.08 | 388,188
LinqImutableReturn | 0.325 ms | 0.007 ms | 0.25 | 1,117,130
LinqReturn | 0.347 ms | 0.002 ms | 0.07 | 1,195,351


Scale : 100,000
Name | Time | Range | StdDev | Cycles
---------------------------------------------------------------------------
ForLoopByRef | 0.635 ms | 0.168 ms | 0.11 | 2,215,066
ForLoopImutableReturn | 0.867 ms | 0.175 ms | 0.10 | 3,027,096
ForLoopReturn | 0.890 ms | 0.225 ms | 0.09 | 3,109,831
LinqReturn | 2.957 ms | 0.166 ms | 0.17 | 10,347,672
LinqImutableReturn | 3.084 ms | 0.219 ms | 0.40 | 10,780,304


Scale : 1,000,000
Name | Time | Range | StdDev | Cycles
-----------------------------------------------------------------------------
ForLoopByRef | 6.624 ms | 1.685 ms | 0.83 | 23,156,409
ForLoopImutableReturn | 9.574 ms | 1.678 ms | 0.82 | 33,503,375
ForLoopReturn | 9.811 ms | 2.290 ms | 0.86 | 34,324,963
LinqImutableReturn | 32.463 ms | 1.401 ms | 1.11 | 113,246,111
LinqReturn | 32.973 ms | 0.830 ms | 1.18 | 114,892,311

总结

我对这些结果持保留态度。当您查看高性能代码时,事情并没有那么清晰。但这个故事的寓意是,如果您追求性能而不是可读性和可维护性,则需要在现实情况下对代码进行基准测试。

关于c# - 如何在 foreach 循环中修改结构的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50282468/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com