我有一个 MainForm
和 UserConfigForm
,并使用此答案中的模式用于 UserConfigForm
,即。
private static UserConfigForm openForm = null;
public static UserConfigForm GetInstance()
{
if (openForm == null)
{
openForm = new UserConfigForm();
openForm.FormClosed += delegate { openForm = null; };
}
return openForm;
}
在UserConfigForm
内部,我也有一个自动质体UserHasSaved
即。
public bool UserHasSaved { get; private set; }
现在,在MainForm
中,我需要检查是否必须在关闭配置表单时重新加载用户配置。所以在MainForm
中,我有
private UserConfigForm userCfgForm;
private void OpenEditFormClick(object sender, EventArgs e)
{
userCfgForm = UserConfigForm.GetInstance();
userCfgForm.FormClosed += ConfigFormClosed;
userCfgForm.Show();
{
private void ConfigFormClosed(object sender, FormClosedEventArgs e)
{
if (userCfgForm.UserHasSaved)
{
MessageBox.Show(message, caption);
//Reload config
}
}
问题在于这起作用,但我不明白为什么会这样。我有两个事件处理程序注册到FormClosed
,所以我认为处理哪个订单活动处理程序是谨慎的。
看来,事件处理程序是按照注册的顺序处理的。因此,我可以在delegate { openForm = null }
之后访问userCfgForm.UserHasSaved
是没有意义的。
我应该为此担心还是很高兴它有效?
您对参考类型的变量在c#中的工作方式有误解。
。让我们看一个更简单的示例:
class F1
{
static int x = 0;
public static int Start()
{
x = 1;
return x;
}
public static void Stop()
{
x = 0;
}
}
class F2
{
int y;
void DoIt()
{
this.y = F1.Start();
F1.Stop();
Console.WriteLine(this.y);
}
}
假设我们在F2实例上调用DOIT。this.y
的值是多少?
通过程序的动作进行跟踪:
- f1.x开始为零。
- f2.doit调用f1.start()
- f1.x变为1
- f1.start()返回1
- f2.y变为1
- f2.doit调用f1.stop()
- f1.x变为0
f2.y仍然是1.更改F2.X并没有更改有关f2.y的任何内容。这是一个完全不同的变量。我们没有创建任何一种神奇的连接,说"当您阅读f2.y时,真正读取f2.x的当前值"。
您的程序也是如此。我们可以将其更改为参考类型,没有任何更改:
class F1
{
public static F1 x = null;
public static F1 Start()
{
x = new F1();
return x;
}
public static void Stop()
{
x = null;
}
}
class F2
{
F1 y;
void DoIt()
{
this.y = F1.Start();
F1.Stop();
Console.WriteLine(this.y == null); // false
}
}
会发生什么?同样的事情。
- f1.x以null。 开始
- f2.doit调用f1.start()
- f1.x成为对有效对象的引用
- f1.start()返回对有效对象的引用
- f2.y成为对有效对象的引用
- f2.doit调用f1.stop()
- f1.x变为null
什么是f2.y?仍然是对有效对象的引用。f2.y是从不参考f1.x。它们都是对同一有效对象的引用。参考是值,就像整数一样。
现在,如果您想要对变量有一个别名,则C#7让您这样做:
class F1
{
static int x = 0;
public static ref int Start()
{
x = 1;
return ref x;
}
public static void Stop()
{
x = 0;
}
}
class F2
{
void DoIt()
{
ref int y = ref F1.Start();
F1.Stop();
Console.WriteLine(y); // 0
}
}
ref
表示本地变量y是变量f1.x 的别名,因此,当我们更改F2.x
时,我们还会更改y
,因为它们只是两个 names 对于相同的变量;它们是 cliased 。
请注意,变量的别名与变量的类型无关。您可以对int变量制造一个别名,无论如何,都可以使对象变量成为一个别名。别名变量和混叠本地必须具有完全相同的类型(练习:为什么?),但是这种类型可以是您想要的。
规则是:别名变量可以是任何变量;混叠变量只能是本地或正式参数。例如,没有办法制作" ref int"字段。请注意, ref int y
是 local ,而不是 field 。
返回变量别名是一个高级功能,我们多年来一直在辩论它是否正确地添加到C#。您不应使用此功能,直到您对C#中的参考语义有深入的了解。