代码之家  ›  专栏  ›  技术社区  ›  skwear

为什么在窗体关闭并为null后,我仍然可以访问窗体属性?

  •  -1
  • skwear  · 技术社区  · 7 年前

    我有一个 MainForm 和a UserConfigForm 并使用 this 回答 用户配置表单 i、 e。

    private static UserConfigForm openForm = null;
    
    public static UserConfigForm GetInstance() 
    {
        if (openForm == null)
        {
            openForm = new UserConfigForm();
            openForm.FormClosed += delegate { openForm = null; };
        }
        return openForm;
    }
    

    在…内 用户配置表单 我还有一辆汽车 UserHasSaved i、 e。

    public bool UserHasSaved { get; private set; }
    

    现在在 主窗体 我需要检查在关闭配置窗体时是否必须重新加载用户配置。所以在 主窗体 我有,

    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 所以我决定谨慎地检查事件处理程序的处理顺序。

    事件处理程序似乎是按照它们注册的顺序进行处理的。所以我不能访问 userCfgForm.UserHasSaved 之后 delegate { openForm = null } 。

    我是应该为此担忧,还是仅仅因为它起作用而感到高兴?

    0 回复  |  直到 7 年前
        1
  •  9
  •   Eric Lippert    7 年前

    对于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。开始()
    • F1。x变为1
    • F1。Start()返回1
    • F2。y变为1
    • F2。DoIt调用F1。停止()
    • 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。开始()
    • F1。x成为对有效对象的引用
    • F1。Start()返回对有效对象的引用
    • F2。y成为对有效对象的引用
    • F2。DoIt调用F1。停止()
    • F1。x变为空

    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的别名。十、 ,所以当我们改变 F2.x ,我们改变 y 还有,因为他们只有两个人 名称 对于 相同的变量 ;他们是 别名 。

    请注意,变量的别名 与变量的类型无关 。您可以为int变量创建别名,也可以为对象变量创建别名,等等。别名变量和别名局部必须具有完全相同的类型(练习:为什么?)但是那种类型可以是你想要的任何类型。

    但规则是: 别名变量可以是任何变量;别名变量只能是局部或形式参数 例如,无法创建“ref int”字段。请注意 ref int y 是一个 地方的 ,不是 领域 。

    返回变量别名是一项高级功能,我们多年来一直在争论是否应该将其添加到C#。 在对C语言中的引用语义有了透彻而深入的理解之前,不应该使用此功能# 。

    推荐文章