使用Action<>时使用递增int的奇怪行为代表

时间:2010-02-09 22:48:20

标签: c#

鉴于以下代码:

class Sample
{
 public static void Run()
 {
     int i = 1;
     Action<int> change = Increment();
     for (int x = 0; x < 5; x++ )
     {
         change(i);
         Console.WriteLine("value=" + i.ToString());
     }
 }

 public static Action<int> Increment()
 {
      return delegate(int i) { i++; };
 }

}

我得到答案:

值= 1  值= 1  值= 1  值= 1  值= 1  值= 1

而不是1,2,3 ...... 6.

这是来自网上的一篇文章,链接到线索,但我无法弄清楚为什么会这样。有人有什么想法吗?

3 个答案:

答案 0 :(得分:6)

您的参数正在按值传递。

撰写i++会将i的值更改为不同的int值(与可变类型不同)。
在委托中写入i++时,您将参数更改为等于不同的int值。但是,这不会影响其值复制到参数的局部变量。

要解决此问题,您需要使用ref参数创建一个委托。 ref参数通过引用传递。因此,当您将ref int参数更改为其他int值时,您还将更改将引用作为参数传递的局部变量或字段。

有关详细信息,请参阅here

由于Action代表不接受ref个参数,您需要制作自己的委托类型,如下所示:

delegate void RefAction<T>(ref T param);

答案 1 :(得分:6)

数据类型 int 是基本数据类型,因此是值类型而不是引用类型。这意味着当您将变量 i 传递给函数时,它不是已传递的实际变量,而是值的副本。因此,当在函数内部更改参数时,它是已更改的本地副本,而不是原始变量。

如果您确定希望该函数能够修改原始变量的值,那么您应该将 ref 关键字添加到函数参数签名中,以告诉编译器您想要将变量作为参考传递。

public void ChangeOriginal(ref int something)
{ something = something + 1;}

public void ChangeLocalCopy(int something)
{something = something + 1;}

我建议您阅读stack vs the heap(值类型与引用类型),因为它是编程时非常基础的主题。

答案 2 :(得分:2)

动作不返回任何内容。它只增加传入的值 - 而不是对原始的引用(如Slaks所说)。您可以使用Func以这种方式执行。

class Sample
{
 public static void Run()
 {
     int i = 1;
     Func<int, int> change = Increment();
     for (int x = 0; x < 5; x++ )
     {
         i = change(i);
         Console.WriteLine("value=" + i.ToString());
     }
 }

 public static Func<int, int> Increment()
 {
      return delegate(int i) { return ++i; };
 }
}