日期:2014-05-18  浏览次数:22393 次

关于“无法访问已释放的对象”,老问题,不知道如何解决
最近做程序,采用定时器加委托方式对进行控制程序如下:



C# code

        System.DateTime oldtime=new DateTime();
        delegate void SetTextCallback(string strTime);//定义托管函数
        System.Timers.Timer t = new System.Timers.Timer(100);//实例化Timer类 
        bool closeFlag;
        public Form1()
        {
            InitializeComponent();
        }
private void timeClass_Click(object sender, EventArgs e)
{
    t.Elapsed+= new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件; 
    t.AutoReset = true;//设置是执行一次(false)还是一直执行(true); 
    t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; 
   
}
public void theout(object source, System.Timers.ElapsedEventArgs e) //定时器调用
{

    System.DateTime currentTime = new DateTime();
    currentTime = DateTime.Now;
    string ss = (currentTime - oldtime).TotalMilliseconds.ToString();
    oldtime = currentTime;
    AddText(ss);
}

void AddText(string strTime)
{
        //在此处使用过:this.isDisposed和this.Disposing进行判定,无法解决    
        if (this.listView1.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(AddText);         
            this.Invoke(d, new object[] { strTime });//此处出现,无法释放问题
        }
        else
        {
            string[] str = { listView1.Items.Count.ToString(), "测试", strTime };
            ListViewItem item = new ListViewItem(str);
            listView1.Items.Add(item);
        }  
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
  
    t.Close();//这个地方如果增加一个关闭t.close的话也不行,定时器整个form关闭前没有被关闭!
    Thread.Sleep(500);
}





程序的主要思想在定时器的状态下,向listview表中写数据,现在问题是,如果程序关闭的时候,定时器不会关闭,这个时候往list中写数据,会提示From已被释放。

在网上也看了很多类似的帖子,主要方法如下:
1、使用this.isDisposed,this.Disposing进行判定
2、在退出的时候增加一个判定的变量,如quitFlag
3、退出的时候增加一个sleep也不行,总是感觉我的from被关闭的时候,定时器还没有被关闭
以上方法都做过测试了,都不行!

以上还有没有更好的方法,目前测试要是能在from关闭前!!完全!!关掉定时器,程序退出就没有问题!
不要给我说用try...catch,这个根本就不是一个解决方法,说Try...catch的不给分,吼吼。



------解决方案--------------------
改成
this.BeginInvoke(d, new object[] { strTime })
------解决方案--------------------
你这种写法是不对的
AddText 方法中
SetTextCallback d = new SetTextCallback(AddText);
this.Invoke(d。。。

也就意味着 this.listView1.InvokeRequired==true时
之前所调用的所有的 AddText方法体(包括其中的 SetTextCallback)都不会释放掉
也就是说 如果this.listView1.InvokeRequired一直保持为true状态的话
会使无数个AddText 不能释放 最后形成无限递归

而 while 不同 它占用的资源不会因为 循环的次数不同 而 变化
建议你用另起线程循环 而不是 另起线程递归
(t.Elapsed+= new System.Timers.ElapsedEventHandler(theout)实际上是另起线程执行)

以上致使 关闭窗口后无法释放掉该方法体 该方法体还需要form窗体资源
所以会出现"访问已经释放的资源"异常
你把 Invoke 改为BeginInvoke 其实资源还是没有释放掉
 但是由于非主线程的异常 不会为主线程捕获到 所以你没有获得异常信息

所以 要做在某一段时间内 无限执行的东西 用 while 不要用 递归
------解决方案--------------------
如楼上,使用递归确实要注意,能不用就别用,用最普通的方法实现
------解决方案--------------------
一步到位

System.Environment.Exit(0);