如何处理缺少调用的方法

本文关键字:调用 方法 何处理 处理 | 更新日期: 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 之前检查表单是否已关闭或处置。

也就是说,您的设计似乎存在一些问题。

  1. 您正在从线程池调用 SetGridDataSource,但它可能应该从 UI 线程调用。
  2. 您没有正确链接异步调用。具体来说,您不会在第二个BeginInvoke上呼叫EndInvoke
  3. 可以帮助您正确处理线程的一个好方法是使用类似 BackgroundWorker 的东西,而不是链接BeginInvoke调用。
  4. 请考虑将业务逻辑(包括线程和异步逻辑(从 UI 层和窗体移开。
  5. 在没有异常类型的情况下执行catch是一个非常糟糕的主意,并且通过忽略它而不重新引发来处理任何抛出的异常。

顺便说一句,与其这样做:

BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);

你可以执行以下操作,我认为这更具可读性:

BeginInvoke(SetGridDataSource, dataSource);