动作参数范围
Scope of Action parameters
我一直在开发一个 WPF 应用程序,我偶然发现了一些有趣的东西,可能是因为我不知道它到底是如何工作的。
基本上我正在创建一个上下文菜单。菜单有一个parent个MenuItem,其中有3个children同类型。这是最基本的代码。
public MainWindow()
{
InitializeComponent();
ContextMenu ctxMain = new ContextMenu();
MenuItem parent = CreateMenuItem("Parent", null);
for(int i = 0; i < 3; i++)
{
parent.Items.Add(CreateMenuItem(i.ToString(), () => MessageBox.Show(i.ToString())));
}
ctxMain.Items.Add(parent);
this.ContextMenu = ctxMain;
}
public MenuItem CreateMenuItem(string header, Action action)
{
MenuItem item = new MenuItem();
if (action != null)
{
item.Click += (object sender, RoutedEventArgs e) => action();
}
item.Header = header;
return item;
}
从视觉上看,它按预期工作。
但是我作为参数给出的操作表现得很奇怪。我希望每个 child 项目的点击都能在 MessageBox 中显示其 header 中所写的内容。但是他们都显示'3'。
我的理解是否正确,我在 for 循环中定义的内联操作没有被实例化三次,而是只有一次,使用相同的参数 'i'?或者它们是三个不同的 Action 实例,都引用同一个整数?我想听听对这里发生的事情的一些澄清。
提前致谢。
问候。
for(int i = 0; i < 3; i++)
{
var localCopy = i;
parent.Items.Add(CreateMenuItem(localCopy.ToString(), () => MessageBox.Show(localCopy.ToString())));
}
你的变量 i 是 "captured" 的 lambda 表达式。但是 i
在您的操作执行之前已更改。并且您的操作在当前 i
上执行,这意味着 3(循环后以及您的操作最终执行时 i 的值)。
您需要制作变量的本地副本并改用它。因为它在循环内有自己的作用域,所以它永远不会改变。
我一直在开发一个 WPF 应用程序,我偶然发现了一些有趣的东西,可能是因为我不知道它到底是如何工作的。
基本上我正在创建一个上下文菜单。菜单有一个parent个MenuItem,其中有3个children同类型。这是最基本的代码。
public MainWindow()
{
InitializeComponent();
ContextMenu ctxMain = new ContextMenu();
MenuItem parent = CreateMenuItem("Parent", null);
for(int i = 0; i < 3; i++)
{
parent.Items.Add(CreateMenuItem(i.ToString(), () => MessageBox.Show(i.ToString())));
}
ctxMain.Items.Add(parent);
this.ContextMenu = ctxMain;
}
public MenuItem CreateMenuItem(string header, Action action)
{
MenuItem item = new MenuItem();
if (action != null)
{
item.Click += (object sender, RoutedEventArgs e) => action();
}
item.Header = header;
return item;
}
从视觉上看,它按预期工作。
但是我作为参数给出的操作表现得很奇怪。我希望每个 child 项目的点击都能在 MessageBox 中显示其 header 中所写的内容。但是他们都显示'3'。
我的理解是否正确,我在 for 循环中定义的内联操作没有被实例化三次,而是只有一次,使用相同的参数 'i'?或者它们是三个不同的 Action 实例,都引用同一个整数?我想听听对这里发生的事情的一些澄清。
提前致谢。 问候。
for(int i = 0; i < 3; i++)
{
var localCopy = i;
parent.Items.Add(CreateMenuItem(localCopy.ToString(), () => MessageBox.Show(localCopy.ToString())));
}
你的变量 i 是 "captured" 的 lambda 表达式。但是 i
在您的操作执行之前已更改。并且您的操作在当前 i
上执行,这意味着 3(循环后以及您的操作最终执行时 i 的值)。
您需要制作变量的本地副本并改用它。因为它在循环内有自己的作用域,所以它永远不会改变。