为什么我的INT变量被引用传递? C#

时间:2014-04-16 02:50:14

标签: c# delegates closures pass-by-reference value-type

好的,所以我知道C#中值类型和引用类型之间的区别(我认为)。但是,下面的代码并不像我期望的那样了解我对值类型和引用类型的了解。

delegate void SomeHandler();

static Action GetSomeHandler()
 {
   int x = 1;

   SomeHandler a = delegate { Console.WriteLine(x); };

   x = 2;

   return a;
 }

static void Main(string[] args)
{
   SomeHandler a = GetSomeHandler();

   a();
}

我很困惑因为在我的GetSomeHandler方法中声明了局部变量“x”并将其初始化为1。然后,声明SomeHandler类型的新委托“a”并将其分配给将“x”写入控制台的匿名方法。 然后将“x”分配给2.最后,调用“a”并将“x”的值打印到控制台。

我期望输出为1,因为“x”是一个int(一个值类型),我会假设当2被分配给“x”时它不会影响我在我的委托中使用的因为值会被复制而不是指向内存中的相同位置,但实际输出是2 !!为什么!?

1 个答案:

答案 0 :(得分:3)

啊,你发现了关闭的神奇之处!

你认为" x"是正确的。是一种值类型,它不应该以这种方式运行;也就是说,如果你没有在你的方法中声明一个匿名函数。匿名方法是一个闭包,并且绑定到它的父方法体和它中的局部变量(在这种情况下,它是局部变量" x"以及父方法GetSomeHandler)。

重要的区别在于它绑定到变量,而不是。换句话说," x"的值当" a"被宣布。相反,"参考"到" x"用于使" a"将始终使用" x"的最新值。事实上,这个"参考"到" x"即使" x"超出范围。当你编译你的程序时,编译器然后使用它的一些编译器魔法"并生成类似于以下代码片段的内容:

delegate void SomeHandler();

// This is the helper class generated by the compiler that allows an anonymous function inside your method access to local variables even after the function or method has returned.
sealed class SomeHandlerClosure
{
   public int x;

   public void CompilerNamedMethod()
   {
     Console.WriteLine(x);
   }
}

static SomeHandler GetSomeHandler()
 {
   SomeHandlerClosure closure = new SomeHandlerClosure();
   closure.x = 1;

   SomeHandler a = new SomeHandler(closure.CompilerNamedMethod);

   closure.x = 2;

   return a;
 }

static void Main(string[] args)
 {
   SomeHandler a = GetSomeHandler();

   a();
 }

" GetSomeHandler"方法真的是魔术发生的地方:

1.在方法的开头,是" SomeClosure"的一个实例。类已创建。 (请注意,为了清楚起见,我选择使用名称" SomeHandlerClosure"和" CompilerNamedMethod"实际上,编译器会生成名称以防止名称冲突。)

2.所有对局部变量的引用" x"在" GetSomeHandler"方法已被替换为" x" " SomeHandlerClosure"实例

3.代表" a"现在被分配给" CompilerNamedMethod"的新委托实例。在" SomeHandlerClosure"实例

清除泥浆?