我是c#的新手,所以问题可能有点愚蠢。
我想迭代收集并在适当位置更改它的值(返回对值的引用)。
代码我想看起来像这样:
IEnumerable<int> Iterate(int[] values)
{
foreach (int value in values) { yield return value; }
}
void some()
{
int[] collection = new int[] {1,2,3};
foreach (int elem in Iterate(collection)) {
elem = elem*2;
}
// collection is now a {2,4,6}
}
那么最简单的方法是什么?感谢。
UPD。真正的问题是难以理解的。这只是示例显示我想使用“引用整数”或smth。
我只想在C#中更接近这个C ++代码的类比:
int a[3] = {1, 2, 3};
for (auto& value: a) { value*=2; }
答案 0 :(得分:2)
使用强大的Linq功能。
int[] collection = new int[] {1,2,3}
var modified = collection.Select(i => i * 2).ToArray();
您还可以使用一种方法(在c ++中称为函数)来隐藏更复杂的转换。
int Transform(int input)
{
return input * 2;
}
void Later()
{
collection.Select(Transform);
}
答案 1 :(得分:1)
你的问题有一个简单的答案:那是不可能的。
让我们来看看这个foreach (var item in enumerable)
在幕后如何运作。
当您声明foreach (var item in enumerable) item.DoWork();
时,.NET编译器会将其转换为:
var enumerator = enumerable.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
current.DoWork();
}
}
finally
{
enumerator.Dispose();
}
这有一个重要的事情。只要集合保持不变,创建的枚举器仍然有效。如果对集合进行了更改,例如添加,修改或删除元素,则枚举数将无法恢复,并且下一次调用MoveNext()
将引发InvalidOperationException
。
因此,您无法在通过IEnumerable
循环获取foreach
时对其进行修改。
答案 2 :(得分:0)
使用for:
for(int i=0;i<collection.Length;i++)
{
collection[i]=collection[i]*2;
}
答案 3 :(得分:0)
C ++ for-auto-ref语法也吸引了我,因为(至少出于对值类型对象列表进行就地突变的目的)它比C#中的for-index循环更具表现力。但是,您仍然可以通过隐藏帐簿的“帮助程序”方法在安全的C#中获得类似的表达。例如:
static void For<T>(IList<T> a, Func<T, T> f)
{
for (var i = 0; i < a.Count; ++i)
{
a[i] = f(a[i]);
}
}
// Usage:
int[] a = { 1, 2, 3 }; // "a" can be any type that implements IList<T>
For(a, value => value * 2);
如果已测量这是代码中的热点,则可能需要为数组定义一个类似的重载,以允许编译器和/或运行时更好地进行优化。例如:
// About 65% faster than with IList<T> (according to a rough benchmark on .NET Framework 4.8)
static void For<T>(T[] a, ForBody<T> f)
{
for (var i = 0; i < a.Length; ++i)
{
f(ref a[i]);
}
}
delegate void ForBody<T>(ref T value);
// Usage:
int[] a = { 1, 2, 3 }; // "a" has to be an array
For(a, (ref int value) => value *= 2);
最后,如果在此方法的调用现场性能确实至关重要,则应使用实际的for
语句替换此方法的使用,因为委托调用会增加不小的开销。在我的基准测试中,使用for
语句代替此方法的速度提高了约30%。
此答案曾经有两个基于指针的选项。一个是使用C#7.3的
unmanaged
类型约束的泛型,另一个是非泛型的。与上述在安全代码中使用通用数组的方法(委托在ref T
上进行操作)相比,前者的速度要慢5%,而后者的速度要慢1%。安全代码FTW!
答案 4 :(得分:0)
距离上次更新已经很长时间了。从 C# 7.3 开始,可以在 foreach 中使用 ref locals。结合属性 getter 的 ref 返回,它允许编写如下代码:
void some()
{
int[] collection = new int[] {1,2,3};
foreach (ref int elem in collection.AsSpan())
elem = elem*2;
}
.AsSpan()
调用是必要的,因为 T[] 数组的默认枚举器确实将纯 T 作为 Current 属性返回类型。
Span 类型中的枚举器确实使用 ref T Current {get;}
代替,因此允许根据主题启动器的要求直接修改集合。