为什么Enumerator
不会跟踪同一函数中的项目,但如果MoveNext
操作在其他函数中发生则不会跟踪?
示例:
public static void Test()
{
var array = new List<Int32>(new Int32[] { 1, 2, 3, 4, 5 });
var e = array.GetEnumerator();
e.MoveNext();
e.MoveNext();
Console.WriteLine(e.Current); // 2
Incremenet(e);
Console.WriteLine(e.Current); //2
}
static void Incremenet(IEnumerator<Int32> e)
{
Console.WriteLine("Inside " + e.Current); //2
e.MoveNext();
Console.WriteLine("Inside " + e.Current); // 3
e.MoveNext();
Console.WriteLine("Inside " + e.Current); //4
}
我期望在最后一个CW中获得5分,但是我得到2分,就像它从未增加过一样。当函数返回时,为什么忘记了MoveNext
函数中的Increment
?
干杯。
答案 0 :(得分:6)
List<T>
的枚举器类型List<T>.Enumerator
不是class
,而是struct
。由于GetEnumerator
公开了返回类型为List<T>.Enumerator
,因此当您使用var
时,e
的类型为List<T>.Enumerator
,因此当您将其传递给{{ 1}},它自动boxed成为Incremenet
个对象。这就是你所看到的奇怪行为的原因。
如果您将IEnumerator<Int32>
键入为e
,则只要您获得对象就会发生装箱,因此不会发生这种奇怪的行为:无论您是否运行{中的其他代码,它的工作方式都相同{1}}或IEnumerator<Int32>
(我修正了该方法的拼写,顺便说一下,它不是“Incremenet”)。
Test
出于性能原因,它被公开为类型而不是Increment
。 public static void Test()
{
var array = new List<Int32> { 1, 2, 3, 4, 5 };
IEnumerator<Int32> e = array.GetEnumerator(); // boxed here
e.MoveNext();
e.MoveNext();
Console.WriteLine(e.Current); // 2
Increment(e);
Console.WriteLine(e.Current); // now it's 4
}
static void Increment(IEnumerator<Int32> e)
{
Console.WriteLine("Inside " + e.Current); // 2
e.MoveNext();
Console.WriteLine("Inside " + e.Current); // 3
e.MoveNext();
Console.WriteLine("Inside " + e.Current); // 4
}
is smart enough在这种情况下无需装箱或虚拟调度即可调用IEnumerator<T>
和foreach
,并且可以毫无问题地处理值类型语义。正如你所看到的那样,它确实引起了混乱,因为mutable struct
s are evil已经没有照顾好你的处理方式。
答案 1 :(得分:1)
出于同样的原因,test
在以下测试用例中递增后为1。这是值类型的正常行为。
static void Main(string[] args)
{
int test = 1;
Increment(test);
Console.WriteLine("After increment: " + test);
}
static void Increment(int test)//add ref and the original variable will also update
{
test += 1;
Console.WriteLine(test);
}
正如Servy在技术上指出的那样,该示例的不同之处在于局部变量test
是不可变的。实际上,我们看到的行为是因为变量被复制到Increment
方法。但是,我的观点是这种行为在值类型(属性和局部变量)之间是一致的。有关这一事实的进一步证据:
struct MutableStruct
{
public int EvilInt { get; set; }
}
class Program
{
static void Main(string[] args)
{
var testStruct = new MutableStruct();
testStruct.EvilInt = 1;
int test = 1;
Increment(test, testStruct);
Console.WriteLine("After increment: " + test + " and..." + testStruct.EvilInt);//both 1
}
static void Increment(int test, MutableStruct test2)
{
test2.EvilInt += 1;
test += 1;
Console.WriteLine(test + " and..." + test2.EvilInt);//both 2
}
}
正如我们在这里看到的,这种行为在值类型中是正常的。在局部不可变值类型和可变结构的情况下,行为保持一致。