无法访问已释放的对象C#(showdialog dispose)

本文关键字:showdialog dispose 对象 访问 释放 | 更新日期: 2023-09-27 18:25:45

我是c#的新手,对它有点陌生。使用Microsoft Visual c#2010

我查看了许多类似的帖子,似乎没有任何建议对有帮助

我收到以下错误:"无法访问已处理的对象"它引用了这里的主要形式

private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            RunPackages rp = new RunPackages();    
            this.Hide();
            rp.ShowDialog();//The error points to this line
            this.Show();
        }

这是当安全检查失败时会爆炸的代码。

private void securityCheck()
        {
            if (MyGlobals.FormCheck("RUN_JOBS") == 1)
            {
                InitializeComponent();
            }
            else
            {
                //this.BeginInvoke(new MethodInvoker(this.Close));
                //this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
                MessageBox.Show("You do not have permission to access this form!");
                //this.Close();
                this.Dispose();
            }            
        }

编辑看起来我会同意阿德里亚诺·雷佩蒂的想法,把安全性放在我称之为页面的地方,但现在页面上有任何安全性,我有点紧张。

   private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("RUN_JOBS") == 1)
            {
                RunPackages rp = new RunPackages();
                this.Hide();
                rp.ShowDialog();
                this.Show();                
            }
            else
            {
                MessageBox.Show("Not for You!");             
            }
        }
        private void btn_ListUpdater_Click(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM") == 1)
            {
                ListUpdater lu = new ListUpdater();
                this.Hide();
                lu.ShowDialog();
                this.Show();
            }
            else
            {
                MessageBox.Show("Private!");
            }            
        }

编辑2提出了以下可能的解决方案,但我很紧张地使用它,因为我是这方面的新手,不知道可能会有什么问题。只为表单加载创建一个事件处理程序有什么问题吗?

namespace RunPackages
{
    public partial class ListUpdater : Form
    {
        public ListUpdater()
        {            
            InitializeComponent();
            this.Load += new EventHandler(securityCheck);
        }    
        private void securityCheck(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM1") == 0)
            {
                MessageBox.Show("Not Allowed!");
                this.Close();
            }    
        }

无法访问已释放的对象C#(showdialog dispose)

您不能在表单本身中处理表单。ShowDialog()方法尝试在出口时访问窗体以获取DialogResult之类的内容。

表单被处理后,几乎所有的方法都无法访问(并且它的大多数属性都无效)。

btn_RunPkgs_Click()的第一行中,您创建了一个对象,并在其构造函数中对其进行处理本身,即使你的坏习惯甚至可能从构造函数中调用Dispose(),它甚至可能工作,但如果你尝试使用这样的对象,ShowDialog()将生成ObjectDisposedException。请注意,此代码也将导致相同的结果(异常):

RunPackages rp = new RunPackages();
rp.Dispose();

是的,你可以检查IsDisposed,但这不会使代码可读,问题(IMO)是你在混合东西。构造函数不应该包含这样的逻辑。

重点不仅仅是在处理表单。更好的是甚至不要创建这样的表单(让我假设,因为你调用InitializeComponent(),所以securityCheck()在表单构造函数内部调用),为此你可以使用一个工厂静态方法:

public static bool TryShowDialog(Form currentForm)
{
    if (MyGlobals.FormCheck("RUN_JOBS") != 1)
        return false;
    if (currentForm != null)
        currentForm.Hide();
    RunPackages dlg = new RunPackages();
    dlg.ShowDialog();   
    if (currentForm != null)
        currentForm.Show();
    return true;
}

然后,您的呼叫功能将减少为:

private void btn_RunPkgs_Click(object sender, EventArgs e)
{
    RunPackages.TryShowDialog(this);
}

请注意,这样的函数非常适合进行某些重构(例如提取代码以隐藏/显示现有表单)。类似这样的东西:

public static bool ShowDialog<T>(Form currentForm, string authorizationId)
    where T : Form, new()
{
    if (MyGlobals.FormCheck(authorizationId) != 1)
        return false;
    if (currentForm != null)
        currentForm.Hide();
    T dlg = new T();
    T.ShowDialog();   
    if (currentForm != null)
        currentForm.Show();
    return true;
}

这样使用(现在代码在任何地方都可以重复使用):

    SecurityHelpers.ShowDialog<RunPackages>(this, "RUN_JOBS");

请注意,调用代码可能会被简化(例如,authorizationId可能是RunPackages上的属性,并且currentForm也可以从当前的活动形式中推导出来)。

EDIT调用Close()并没有更好,如果窗口句柄尚未在内部创建(让我们稍微简化一下:它是在显示窗口时创建的),它将调用Dispose()(然后以上适用)。

我不会试图破坏导致表单创建的事件的链接
副作用很难预测,目前有效的方法在未来的版本中也不起作用。

相反,我会尝试一种不同的方法

    private void securityCheck()
    {
        if (MyGlobals.FormCheck("RUN_JOBS") == 1)
        {
            InitializeComponent();
        }
        else
        {
            Label message = new Label();
            message.Dock = DockStile.Fill;
            message.Text("You do not have permission to access this form!.");
            message.TextAlign = ContentAlignment.MiddleCenter;
            this.Controls.Add(message);
        }      
    }

通过这种方式,我让表单只显示一个标签,该标签覆盖了包含消息的整个表单表面。用户只能关闭表单(前提是您没有移除控制框)

顺便说一句,这有避免危险疏忽的优点,因为它不需要对调用代码进行任何更改,最终效果是有效地阻止表单的使用。

如果你坚持在表单的构造函数阶段关闭表单,那么你可以从这个问题中得到一些建议

我想到了以下内容,有人能告诉我这是否有任何问题吗?

namespace RunPackages
{
    public partial class ListUpdater : Form
    {
        public ListUpdater()
        {            
            InitializeComponent();
            this.Load += new EventHandler(securityCheck);
        }    
        private void securityCheck(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM1") == 0)
            {
                MessageBox.Show("Not allowed!");
                this.Close();
            }    
        }

等等。。。

使用标志。例如,更改代码,如下所示:

    public bool IsDisposed;
    private void securityCheck()
            {
                if (MyGlobals.FormCheck("RUN_JOBS") == 1)
                {
                    InitializeComponent();
                }
                else
                {
                    //this.BeginInvoke(new MethodInvoker(this.Close));
                    //this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
                    MessageBox.Show("You do not have permission to access this form!");
                    //this.Close();
                    this.Dispose();
                    this.IsDisposed = true;
                }      

        }

然后:

private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            RunPackages rp = new RunPackages();    
            if(rp.IsDisposed)
                return;
            this.Hide();
            rp.ShowDialog();//The error points to this line
            this.Show();
        }