鉴于以下代码:
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.
这是来自网上的一篇文章,链接到线索,但我无法弄清楚为什么会这样。有人有什么想法吗?
答案 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; };
}
}