C# 中对"Cross-thread operation not valid"错误的处理办法

概要
Windows Forms控件通常不是thread-safe,它是直接或间接继承于System.Windows.Forms.Control的。因此.NETFramework为防止multithread下对控件的存取可能导致控件状态的不一致,在调试时,CLR-Debugger会抛出一个InvalidOperationExceptio n以‘建议‘程序员程序可能存在的风险。

问题的关键在于,动机是什么?和由此而来的编程模型的调整。
1.Example
首先,看一个代码实例。该例要完成的工作是由一个Button的Click触发,启动一个Thread(ManualThread),该Thread的目的是完成设置TextBox的Text’s Property。
1.1 Unsafeaccess to control
 
Code 1.1
using System;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
 
namespace WindowsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }
 
        private void unsafeSetTextButton_Click(object sender, EventArgs e) {
            Thread setTextThread = new Thread(new ThreadStart(doWork));
            setTextThread.Start();
        }
 
        private void doWork() {
            string fileName = ".\\test-src.txt";
            if (!File.Exists(fileName)) {
                MessageBox.Show(string.Format("{0} doesn't exist!", fileName),
                    "FileNoFoundException");
                return;
            }
 
            string text = null;
            using (StreamReader reader = new StreamReader(fileName, Encoding.Default)) {
                text = reader.ReadToEnd();
            }
 
            this.textBox1.Text = text;
        }
    }
}

在调试时,CLR-Debugger会在以上代码中粗体处将会弹出如下的对话框:



提示说,当前存取控件的thread非创建控件的thread(MainThread)。
 
 
1.2 What’smean?
当然,你也可以忽略InvalidOperationExceptio n,在非调试的状态下,该异常并不会被抛出,CLR-Debugger监测对Handle的可能存在的不一致地存取,而期望达到更稳健(robust)的代码,这也就是Cross-threadoperation not valid后的真正动机。
 
但是,放在面前的选择有二:第一,在某些情况下,我们并不需要这种善意的‘建议‘,而这种建议将在调试时带来了不必要的麻烦;第二,顺应善意的‘建议‘,这也意味着我们必须调整已往行之有效且得心应手的编程模型(成本之一),而这种调整额外还会带来side-effect,而这种side-effect目前,我并不知道有什么简洁优雅的解决之道予以消除(成本之二)。
 
2. The firstchoice : CheckForIllegalCrossThreadCalls
忽略Cross-threadInvalidOperationExceptio n建议,前提假设是我们不需要类似的建议,同时也不想给自己的调试带来过多的麻烦。
 
关闭CheckForIllegalCrossThre adCalls,这是Controlclass上的一个staticproperty,默认值为flase,目的在于开关是否对Handle的可能存在的不一致存取的监测;且该项设置是具有Applicationscope的。
 
如果,只需要在某些Form中消除Cross-threadInvalidOperationExceptio n建议,可以在Form的.ctor中,InitializeComponent语句后将CheckForIllegalCrossThre adCalls设置为false。
Code 2. - 1
static void Main() {
    Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
 
Control.CheckForIllegalCrossThreadCalls = false;
 
    Application.Run( new Form1() );
}

这种方式虽然可以达到忽略Cross-threadInvalidOperationExceptio n建议的目的,但代码不能明晰的表达具有Applicationscope的语义,下面方式能更好的表达Applicationscope语义而且便于维护。
 
Code 2. - 2
static void Main() {
    Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
 
Control.CheckForIllegalCrossThreadCalls = false;
 
    Application.Run( new Form1() );
}


你可能感兴趣的:(thread,编程,String,C#,textbox,Forms)