繁体   English   中英

C#的空引用问题

[英]null reference problems with c#

在我的一种窗口形式中,我创建了一个类的实例,以在后台执行一些工作。 我想捕获该类中的调试消息,并显示在窗口形式的文本框中。 这是我所做的:

class A //window form class
{
   public void startBackGroundTask()
   {
      B  backGroundTask = new B(this);
   }

   public void updateTextBox(string data)
   {
        if (data != null)
        {
            if (this.Textbox.InvokeRequired)
            {
                appendUIDelegate updateDelegate = new appendUIDelegate(updateUI);

                try
                {
                    this.Invoke(updateDelegate, data);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
            else
            {
                updateUI(data);
            }
        } 
   }

    private void updateUI(string data)
    {
        if (this.Textbox.InvokeRequired)
        {
            this.Textbox.Invoke(new appendUIDelegate(this.updateUI), data);
        }
        else
        {
            //update the text box
            this.Textbox.AppendText(data);
            this.Textbox.AppendText(Environment.NewLine);
        }
    }

    private delegate void appendUIDelegate(string data);
}

class B // background task
{
   A curUI;

   public b( A UI)
   {
      curUI = UI;
   }

   private void test()
   {
      //do some works here then log the debug message to UI.
      curUI.updateTextBox("message);
   }
}

我不断收到空引用异常

this.Invoke(updateDelegate, data);

叫做。

我知道传递“ this”作为参数很奇怪,但是我想将调试消息发送到我的窗口表单。

两件事情:

1)考虑使用扩展方法,这样您就不会在所有这些调用上重复自己:

public static class ControlExtentions
{
    public delegate void InvokeHandler();
    public static void SafeInvoke(this Control control, InvokeHandler handler)
    {
        if (control.InvokeRequired)
            control.Invoke(handler);
        else
            handler();
    }
}

2)考虑使用事件使其更具可读性。 使用如下设计:

class B
{
    public event EventHandler LogGenerated = delegate { };

    void test()
    {
        LogGenerated("Some log text", EventArgs.Empty);
    }
}

class A : Control
{
    public A()
    {
        B b = new B();
        b.LogGenerated += new EventHandler(b_LogGenerated);
    }

    void b_LogGenerated(object sender, EventArgs e)
    {
        this.SafeInvoke(() => { textBox1.Text += (String)sender; });
    }
}

不要让调用SafeInvoke的语法给您带来太多麻烦。 它只是代表InvokeHandler委托的lambda。

您在问题中描述的逻辑不会产生空引用异常,这表明该异常来自您正在执行的后台任务,而不是来自UI更新逻辑。

作为证据,这是一个完整的示例,可以简化,但基于您描述的模式:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void updateTextBox(string data)
    {
        if (this.textBox1.InvokeRequired)
        {
            this.Invoke(new MethodInvoker(() => updateTextBox(data)));
            return;
        }

        if (data == null)
        {
            return;
        }

        //update the text box
        this.textBox1.AppendText(data);
        this.textBox1.AppendText(Environment.NewLine);
    }

    private void _uxStartBgTask_Click(object sender, EventArgs e)
    {
        new Thread(() => updateTextBox("message")).Start();
    }
}

请注意,使用MethodInvoker无需声明委托成员,并且立即递归是解决InvokeRequired模式的便捷方法。

看来您有一个无限循环。 updateTextBox构造一个用于调用updateUI的委托,而updateUI构造一个用于updateUI的委托。 是什么在这里阻止无限递归?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM