IntegersTreatedasReferenceTypesWhenPassedtoDelegates本周我参加了在荷兰举行的TechDays2013,我得到了一个有趣的测验问题。问题是:以下程序的输出是什么。代码如下所示。类程序{委托voidWriter();staticvoidMain(string[]args){varwriters=newList();对于(inti=0;i<10;i++){作家。添加(委托{Console.WriteLine(i);});}foreach(Writerwriterinwriters){writer();}}}显然,我给出了错误的答案。我认为,因为int是一种值类型,所以传递给Console.WriteLine()的实际值被复制,所以输出将为0...9。但在这种情况下,我被作为引用类型处理。正确答案是它会显示10次10。有人可以解释为什么以及如何吗?我认为,由于int是一种值类型,因此传递给Console.WriteLine()的实际值会被复制,这是完全正确的。当您调用WriteLine时,该值将被复制。那么,什么时候调用WriteLine?它不在for循环内。那时你没有写任何东西,你只是在创建一个委托。它不会将变量i中的值复制到堆栈,直到您调用委托的foreach循环来调用WriteLine。那么,在foreach循环中i的值是多少?foreach循环的每次迭代都是10。所以现在你问,“好吧,foreach循环中发生了什么,是不是超出了范围iforeach循环,是不是超出了范围。嗯,不,不是。这证明了什么是”关闭的package"。当匿名方法引用一个变量时,这个变量的作用域需要和匿名方法的作用域一样长,可以是任何时间段。如果没有什么特别的,那么读取这个变量就是随机垃圾,包括内存中发生的事情thatAnythinginposition.C#积极确保这不会发生。那它是做什么用的呢?它创建了一个闭包类;它是一个包含许多字段的类,代表所有已关闭的字段。换句话说,代码将被重构为如下所示:publicclassClosureClass{publicinti;publicvoidDoStuff(){Console.WriteLine(i);}}classProgram{delegatevoidWriter();staticvoidMain(string[]args){varwriters=newList();ClosureClassclosure=newClosureClass();for(closure.i=0;closure.inowweallhaveananonymousmethodname(allanonymousmethodsaredefinedbythecompilergivenaname),我们可以确保只要委托引用匿名函数,变量就会存在存在。看看这个重构器,我希望清楚为什么结果被10打印10次。这是因为它是一个捕获的变量。请注意,这也经常发生在foreach中,但在C#5中发生了变化。但是要重写实际拥有的代码:classProgram{delegatevoidWriter();classCaptureContext{//由编译器生成并命名为publicinti;//在C#中是非法的,这真是太可怕了publicvoidDoStuff(){Console.WriteLine(i);}}staticvoidMain(string[]args){varwriters=newList();varctx=newCaptureContext();for(ctx.i=0;ctx.i如你所见:只有一个ctx因此只有一个ctx.i而当你有作家ctx.i它只有10。顺便说一句,如果你想让旧代码工作:for(inttmp=0;tmp基本上,捕获上下文的范围与变量的范围相同;这里变量在循环中的范围内,所以这个产生:for(inttmp=0;tmp这里每个DoStuff都在不同的捕获上下文实例上,因此具有不同且独立的i。在您的情况下,委托方法是访问局部变量的匿名方法(forloopindexi)。也就是说,这些都是clousures,由于匿名方法在for循环后被调用了十次,得到的是最新的i值。a=1;Actiona1=()=>Console.WriteLine(a);Actiona2=()=>Console.WriteLine(a);Actiona3=()=>Console.WriteLine(a);a=2;//这将打印`a`(2)变量的最新分配值的3倍,而不是//仅1。a1();a2();a3();请参阅StackOverflow上的其他问答(.NET中有什么?),了解有关C#/.NET闭包的更多信息!对我来说,通过使用原生Action类而不是自定义Writer来比较旧行为和新行为更容易理解。在for、foreach变量和局部变量捕获的情况下,在C#5闭包之前捕获相同的变量(不是变量的值)。所以给定代码:varanonymousFunctions=newList();varlistOfNumbers=Enumerable.Range(0,10);for(intforLoopVariable=0;forLoopVariable我们只看到为变量forLoopVariable设置的最后一个值。但是,对于C#5,foreach循环已被修改。现在我们捕获不同的变量。例如anonymousFunctions.Clear();//C#5foreach循环捕获foreach(variinlistOfNumbers){anonymousFunctions.Add(delegate{Console.WriteLine(i);});//输出整个数字范围}foreach(ActionwriterinanonymousFunctions){writer();}因此输出更直观:0,1,2...请注意,这是一个重大更改(尽管假定它是一个小更改)。这可能就是for循环行为在C#5中没有改变的原因。以上是C#学习教程:传递给delegate时,整数作为引用类型处理所有的共享内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注---本文来自网络收集,不代表立场,如涉及侵权,敬请谅解点击右侧联系管理员删除。如需转载请注明出处:
