如何处理缺少调用的方法
本文关键字:调用 方法 何处理 处理 | 更新日期: 2023-09-27 18:22:14
public void RefreshData()
{
// this is called on UI thread
List<ds> dataSource;
GetDsDelegate caller = GetDs;
caller.BeginInvoke(out dataSource, RefreshCallback, null);
}
private void RefreshCallback(IAsyncResult ar)
{
// this is called on worker thread
try
{
var result = (AsyncResult)ar;
var caller = (GetDsDelegate)result.AsyncDelegate;
List<ds> dataSource;
var success = caller.EndInvoke(out dataSource, ar);
if (success)
{
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
}
}
catch
{
// NOTE: It's possible for this form to close after RefreshData is called
// but before GetDs returns thus the SetGridDataSource method no longer exists.
// Not catching this error causes the entire application to terminate.
}
private void SetGridDataSource(List<ds> dataSource)
{
// this is called on UI thread
dataGrid.DataSource = dataSource;
}
RefreshData、RefreshCallback 和 SetGridDataSource 都是 Windows Form 类的方法。 调用 RefreshData 将使用 GetDsDelegate 委托调用外部方法 GetD。 当 GetD 完成时,它会调用 RefreshCallback(现在在单独的线程上(。 最后,调用 SetGrid数据源来完成更新。
除非 GetD 延迟并且表单关闭,否则所有这些都可以正常工作。 然后,当 GetD 完成并调用 RefreshCallback 时,SetGridDataSource 将不再存在。
除了显示的 try/catch 块之外,是否有更好的方法来处理这种情况? 我宁愿防止错误而不是忽略它。 有没有更好的模式可以使用?
编辑
当我看到错误时,很明显将if (success)
更改为if (success && IsHandleCreated)
以防止它,但似乎我仍然做错了什么,或者至少很尴尬。 我也可以用 Invoke 替换第二个 BeginInvoke,这样 EndInvoke 就没有必要了。 我喜欢将逻辑从形式中移开的想法,但我看不出结果会如何变化。 我认为背景工作者也会遇到同样的问题;作为回调不再可访问。 我想可以用结果引发一个事件,但这似乎有点抽象。 您能否再详细说明一下或提供一个例子。
该方法确实存在。窗体已关闭的事实不会更改类或其方法。如果您发布您得到的确切异常,它可以帮助某人提供更准确的帮助。
我猜当你在窗体或其控件关闭后尝试对它执行某些操作时,您会得到ObjectDisposedException
。
如果是这种情况,您只需增强逻辑并在调用 SetGridDataSource 之前检查表单是否已关闭或处置。
也就是说,您的设计似乎存在一些问题。
- 您正在从线程池调用 SetGridDataSource,但它可能应该从 UI 线程调用。
- 您没有正确链接异步调用。具体来说,您不会在第二个
BeginInvoke
上呼叫EndInvoke
。 - 可以帮助您正确处理线程的一个好方法是使用类似
BackgroundWorker
的东西,而不是链接BeginInvoke
调用。 - 请考虑将业务逻辑(包括线程和异步逻辑(从 UI 层和窗体移开。
- 在没有异常类型的情况下执行
catch
是一个非常糟糕的主意,并且通过忽略它而不重新引发来处理任何抛出的异常。
顺便说一句,与其这样做:
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
你可以执行以下操作,我认为这更具可读性:
BeginInvoke(SetGridDataSource, dataSource);