引发线程事件时无法访问已处置的对象
Posted
技术标签:
【中文标题】引发线程事件时无法访问已处置的对象【英文标题】:Cannot access a disposed object when raising a threaded event 【发布时间】:2016-10-12 16:24:15 【问题描述】:我正在编写的类使用多线程,并且我为我的类创建了这个扩展方法,以便以线程安全的方式引发事件。
static class MultiThreadHelper
public static object Raise(this MulticastDelegate eventToRaise, object sender, EventArgs e)
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = eventToRaise;
if (threadSafeMulticastDelegate != null)
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] sender, e ));
else
retVal = d.DynamicInvoke(new[] sender, e );
//Return the value of the event invocation or null if none.
return retVal;
当我的表单试图关闭一个挥之不去的线程时,它仍在尝试返回并引发一个不再有处理程序的事件。
我最终得到以下错误...
在该行错误发生之前我可以运行哪种检查?还有什么我可以做的或者我可以采取不同的方法来解决这个问题吗?
【问题讨论】:
【参考方案1】:我的第一个想法是ManifestBuilder
在代理关闭时不会取消订阅。确保使用 -=
语法取消订阅。
【讨论】:
我在 ManifestBuilder 的 FormClosing 事件中这样做了。但我把它作为事件块中的最后一个动作。当我把它作为事件块中的第一个动作时,它似乎提升了这个问题。我认为我的错误是让用户在我处理类对象之前取消订阅......虽然我不明白为什么这很重要。 深入研究... 在 FormClosing 事件中,我将尝试调用将创建新线程的类的方法。然后,一旦创建了新线程,我就会取消订阅。然后......一旦线程完成它会发送一个事件(认为有一个订阅)。在处理多线程时,有什么方法可以检查任何订阅是否处于活动状态?我的问题很简单,订阅事件 -> 强制线程在计时器上发送事件 -> 取消订阅 -> 认为有订阅但没有订阅可以去的事件触发。 在进一步检查您的代码时,我会调查您在哪里获得对您传递给 Raise 方法的 eventToRaise 的引用。我唯一能想到的是,您在处置表单之前的某个时刻分配该变量,并且取消订阅事件,然后在处置表单后使用它。 是的,这似乎正是正在发生的事情......问题是正在传递的“变量”/对象将始终存在。所以检查 null 是一个失败。我从来没有找到一种方法来查看该事件是否有任何订阅,所以我只是简单地将那个调用放在一个 try-catch 块中。 ;) 解决这个问题的更好方法(而不是 try-catch)是确保控件的寿命比线程长。看看这个***问题***.com/questions/1874728/…,他们也有类似的问题。以上是关于引发线程事件时无法访问已处置的对象的主要内容,如果未能解决你的问题,请参考以下文章
通过 Azure 函数注入 DbContext 时无法访问已处置的对象
尝试在 Web API Core 中使用 EF Core 在启动时更新数据库时出现“'无法访问已处置的对象”错误
C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象
System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。'