为什么我的INT变量是通过引用传递的??C#

本文关键字:引用 INT 我的 变量 为什么 | 更新日期: 2023-09-27 17:58:36

好的,所以我知道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!!为什么!?

为什么我的INT变量是通过引用传递的??C#

啊,您发现了闭包的魔力

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

重要的区别在于,它绑定到变量,而不是。换句话说,当声明"a"时,不会复制"x"的值。相反,使用了对"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"类的一个实例。(请注意,为了清晰起见,我选择使用名称"SomeHandlerClose"answers"CompilerNamedMethod"。实际上,编译器生成名称是为了防止名称冲突。)

2."GetSomeHandler"方法中对局部变量"x"的所有引用都已替换为对"SomeHandlerClose"实例上"x"字段的引用。

3.委托"a"现在被分配给"SomeHandlerClose"实例上的"CompilerNamedMethod"的新委托实例。

清澈如泥??