【问题标题】:InvalidOperationException when do a process twiceInvalidOperationException 执行两次处理时
【发布时间】:2023-03-09 09:49:01
【问题描述】:

我必须编写一个异步方法来联系 Web 服务。这是我在 WebServiceHelper 类中的方法:

 public static Task<int> SignIn(string username, string password) 
    {

        try
        {
            TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
            service.LoginCompleted += (object sender, WebService.LoginCompletedEventArgs e) => 
            {
                if (e.Error != null) tcs.SetResult(-1);
                else
                    tcs.SetResult((int)e.Result);

            };
            service.LoginAsync(username, password);
            return tcs.Task;
        }
        catch (Exception ex)
        {

            MessageBox.Show("Error: " + ex.Message);
            return null;
        }

    }

然后我在按钮单击事件中调用它,如下所示:

private async void btLogIn_Click(object sender, RoutedEventArgs e)
    {                       
        try
        {
            int si = await WebServiceHelper .SignIn(tbUsername.Text, tbPassword.Text);               
            if (si != 0) MessageBox.Show("Signed in successfully!");
            else MessageBox.Show("Couldn't sign in");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }            
    }

我第一次点击按钮时效果很好,但是当我再次点击时,出现了错误: “InvalidOperationException,尝试在任务已完成时将其转换为最终状态。”

我做了一些小搜索,在这里找到了一些东西:Tasks seem to start automatically

我知道在重新开始之前我应该​​做一些事情来停止这个过程,但我不知道具体如何以及为什么。有人可以帮我解释一下吗?

【问题讨论】:

  • 你是真的等待方法执行还是多次点击登录按钮?
  • 我确实等到该过程完成然后我单击以再次执行此操作。我认为该过程需要在重新启动之前停止。但我不知道如何阻止它。
  • 该任务应该在您再次点击代码之前完成。您无需手动停止它。查看 Jon Skeet 解决方案如何在您的问题中发布stackoverflow.com/a/4429552/3373870

标签: .net wcf windows-phone-8


【解决方案1】:

我怀疑问题在于您没有取消注册事件处理程序,并且每次调用此方法时,您都会向 service.LoginCompleted 添加一个新的匿名事件处理程序

试试这个

public static Task<int> SignIn( string username, string password )
{
   TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
   EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = null;
   onLoginCompleted = ( object sender, WebService.LoginCompletedEventArgs e ) =>
   {
      service.LoginCompleted += onLoginCompleted;
      if(e.Error != null)
      {
         tcs.SetResult( -1 );
      }
      else
      {
         tcs.SetResult( (int)e.Result );
      }
   };
   service.LoginCompleted += onLoginCompleted;
   service.LoginAsync( username, password );
   return tcs.Task;
}

或者这个

public static Task<int> SignIn( string username, string password )
{
   TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
   EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = ( object sender, WebService.LoginCompletedEventArgs e ) =>
   {
      if(e.Error != null)
      {
         tcs.SetResult( -1 );
      }
      else
      {
         tcs.SetResult( (int)e.Result );
      }
   };
   service.LoginCompleted += onLoginCompleted;
   tcs.Task.ContinueWith(task => service.LoginCompleted -= onLoginCompleted);
   service.LoginAsync( username, password );
   return tcs.Task;
}

顺便说一句,您还应该删除方法周围的通用try/catch,并在所有情况下返回tcs.Task

如果 实际上service.LoginAsync( username, password ) 可能会抛出异常,那么您应该这样做

...
try
{
   service.LoginAsync( username, password );
}
catch(SomeParticularException ex)
{
   tcs.SetException(ex);
}
return tcs.Task;

【讨论】:

    【解决方案2】:

    我尝试使用方法 TrySetResult() 而不是 SetResult() 并且成功了!

    【讨论】:

      猜你喜欢
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      相关资源
      最近更新 更多