.NET开发常见问题两则

一、关于DateTime 在将DateTime类型,插入到数据库的时候,最容易出现的一种错误: “SqlDateTime 溢出。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间” 原因是我们在取DateTime.MinValue的值,并插入到数据库的时候,DateTime.MinValue值范围和数据库DateTime类型数据范围不一致造成的。数据库中,DateTime类型字段,最小值1/1/1753 12:00:00,而.NET Framework中,DateTime类型,最小值为1/1/0001 0:00:00,显然,超出了Sql的值的最小范围,导致数据溢出的错误。

解决方法:使用System.Data.SqlTypes.SqlDateTime.MinValue替代System.DateTime类型,这样SqlDateTime的MinValue和Sql中DateTime的范围吻合,就不会再出现以上的错误了。

二、关于跨线程调用控件的问题 在.NET 2.0中,我们常常需要在新建的线程,比如一个工作线程中访问UI控件,程序编译没有任何错误,但是在运行的时候,会抛出异常:InvalidOperationException,并提示消息:“从不是创建控件 control name 的线程访问它。” 原因是因为:访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问控件非常重要。.NET Framework 有助于在以非线程安全方式访问控件时检测到这一问题。

我们看看有问题的代码:建立新线程,并试图在线程中跨线程调用UI控件
[code]
   private void button1_Click(object sender, EventArgs e)
    {
        Thread thread = new Thread(new ThreadStart(TestFunc));
        thread.IsBackground = true;
        thread.Start();
    }

    private void TestFunc()
    {
        Thread.Sleep(3000);
        label1.Text = "ok!";
    }

  [/code]

  这样在运行的时候,就会抛出InvalidOperationException异常。

解决方法:
方法1.关闭跨线程调用控件的检查,来屏蔽掉此异常
需要将Control.CheckForIllegalCrossThreadCalls 设为 false即可。(不推荐)

方法2.使用Control类的Invoke和BeginInvoke
  为什么使用Invoke和BeginInvoke可以解决问题呢?因为Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。而控件也是在UI线程,所以不存在跨线程调用控件的问题。于是我们有了改进的代码:

[code]
   private void button1_Click(object sender, EventArgs e)
    {
        Thread thread = new Thread(new ThreadStart(TestFunc));
        thread.IsBackground = true;
        thread.Start();
    }

    private void TestFunc()
    {
        Thread.Sleep(3000);
        this.Invoke(new SetLabel(SetLabelText), new string[] { "ok!" });
    }

    private delegate void SetLabel(string s);

    private void SetLabelText(string s)
    {
        label1.Text = s;
    }

  [/code]

建立一个委托,调用Control类的Invoke方法,让UI线程去执行委托实例化的方法。这样就不会出现异常了。
支持原创技术分享,据说打赏我的人,都找到了女朋友!