C# 如何处理缺少调用的方法 public void RefreshData() { //这是在UI线程上调用的 列出数据源; GetDsDelegate调用者=GetDs; BeginInvoke(输出数据源,刷新回调,null); } 私有无效刷新回调(IAsyncResult ar) { //这是在工作线程上调用的 尝试 { var result=(AsyncResult)ar; var caller=(GetDsDelegate)result.AsyncDelegate; 列出数据源; var success=caller.EndInvoke(out-dataSource,ar); 如果(成功) { BeginInvoke(新操作(SetGridDataSource),dataSource); } } 接住 { //注意:调用RefreshData后,此表单可能会关闭 //但是在GetDs返回之前,SetGridDataSource方法不再存在。 //未捕获此错误将导致整个应用程序终止。 } 私有void SetGridDataSource(列表数据源) { //这是在UI线程上调用的 dataGrid.DataSource=数据源; }

C# 如何处理缺少调用的方法 public void RefreshData() { //这是在UI线程上调用的 列出数据源; GetDsDelegate调用者=GetDs; BeginInvoke(输出数据源,刷新回调,null); } 私有无效刷新回调(IAsyncResult ar) { //这是在工作线程上调用的 尝试 { var result=(AsyncResult)ar; var caller=(GetDsDelegate)result.AsyncDelegate; 列出数据源; var success=caller.EndInvoke(out-dataSource,ar); 如果(成功) { BeginInvoke(新操作(SetGridDataSource),dataSource); } } 接住 { //注意:调用RefreshData后,此表单可能会关闭 //但是在GetDs返回之前,SetGridDataSource方法不再存在。 //未捕获此错误将导致整个应用程序终止。 } 私有void SetGridDataSource(列表数据源) { //这是在UI线程上调用的 dataGrid.DataSource=数据源; },c#,asynchronous,C#,Asynchronous,RefreshData、RefreshCallback和SetGridDataSource都是windows窗体类的方法。调用RefreshData使用GetDsDelegate委托调用外部方法GetDs。当GetDs完成时,它调用RefreshCallback(现在在单独的线程上)。最后,调用SetGridDataSource以完成更新 除非GetDs被延迟并且表单关闭,否则所有这些都可以正常工作。然后当GetDs完成并调用RefreshCallback时,SetGridDataSource不

RefreshData、RefreshCallback和SetGridDataSource都是windows窗体类的方法。调用RefreshData使用GetDsDelegate委托调用外部方法GetDs。当GetDs完成时,它调用RefreshCallback(现在在单独的线程上)。最后,调用SetGridDataSource以完成更新

除非GetDs被延迟并且表单关闭,否则所有这些都可以正常工作。然后当GetDs完成并调用RefreshCallback时,SetGridDataSource不再存在

除了显示的try/catch块之外,还有更好的方法来处理这种情况吗?我更愿意防止错误而不是忽略它。有更好的模式可以使用吗

编辑


当我看到错误时,很明显将
if(success)
更改为
if(success&&IsHandleCreated)
以防止这种情况发生,但看起来我还是做错了什么,或者至少有点尴尬。我还可以用just Invoke替换第二个BeginInvoke,这样就不需要EndInvoke。我喜欢将逻辑从表单中移开的想法,但我看不出结果会有什么变化。我认为BackgroundWorker也会有同样的结果问题;回调不再可访问。我想可能会引发一个事件并产生结果,但这似乎有点抽象。请您再详细说明一点或提供一个示例。

该方法确实存在。表单已关闭的事实不会改变类或其方法。如果您发布了确切的异常,您将获得,它可以帮助某人提供更准确的帮助

我猜当您试图在窗体或其控件关闭后对其执行某些操作时,您会遇到一个
ObjectDisposedException

如果是这种情况,您只需增强逻辑,并在调用SetGridDataSource之前检查表单是否已关闭或释放

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

  • 您正在从线程池调用SetGridDataSource,但它可能应该从UI线程调用
  • 您没有正确链接异步调用。特别是,您没有在第二个
    BeginInvoke
    上调用
    EndInvoke
  • 帮助您正确执行线程的一个好方法是使用
    BackgroundWorker
    之类的工具,而不是链接
    BeginInvoke
    调用
  • 考虑将业务逻辑(包括线程和异步逻辑)从UI层和表单中移开
  • 在没有异常类型的情况下执行
    catch
    ,并通过忽略任何抛出的异常而不重试来处理异常,这是一个非常糟糕的主意
  • 顺便说一下,不要这样做:

    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;
    }
    

    .NET 4编译器是否支持最后一个推理示例?我非常确定它在.NET 3.5中不起作用。感谢您的回答。调用SetGridDataSource会生成“在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke”异常。鉴于窗体已关闭,这对我来说是有意义的。这是一个无法解决的争用条件,在所有工作线程完成运行之前,您不能允许窗体关闭。使用BackgroundWorker可以更轻松地完成此操作。
    BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
    
    BeginInvoke(SetGridDataSource, dataSource);