2

私の C# アプリケーションには、同じ呼び出しを何度も行うサービス参照があります。

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;
  service.GetDataCompleted += (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times
  }
  service.GetDataAsync(request);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;
  service.GetDataCompleted += (sender, args) => 
  {
      // do something different here!
  }
  service.GetDataAsync(request);
}

毎回新しいイベントハンドラーを登録するので、これがどういうわけかリークする疑いがあります。それは本当ですか? はいの場合、どうすればそれを回避できますか?

4

1 に答える 1

0

あなたはこれを行うことができます:

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;

  EventHandler handler = null; 
  handler = (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;
  EventHandler handler = null; 

  handler = (sender, args) => 
  {
      // do something different here!

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);
}

編集: 呼び出しをそのハンドラーのみに同期することについて:GetData2()すぐに呼び出した場合GetData()、上記のコードから予測できない結果が得られます。ほとんどの場合、両方のハンドラーが両方のリクエストに対して呼び出されます。

これに対する最も簡単な解決策は、メソッドごとに個別のserviceプロキシ オブジェクトを用意することです。GetDataX()このようにして、両方のリクエストを同時に行うことができます。

ただし、1 つのプロキシ オブジェクトのみを使用する必要があり、同時に要求を行う場合は、間違ったハンドラーが呼び出される可能性があります。1 つのオプションは、UserStateオブジェクトを使用してリクエストを識別することです。これにより、間違ったハンドラーが呼び出された場合でも、間違ったリクエストに対して呼び出されたことを検出できます。

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;

  Guid userState = Guid.NewGuid();

  EventHandler<GetDataCompletedEventArgs> handler = null; 
  handler = (sender, args) => 
  {
      if (userState.Equals(args.UserState)) 
      {
          // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

          //remove itself
          service.GetDataCompleted -= handler;
      }
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request, userState);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;

  Guid userState = Guid.NewGuid();

  EventHandler<GetDataCompletedEventArgs> handler = null; 
  handler = (sender, args) => 
  {
      if (userState.Equals(args.UserState)) 
      {
          // do something different here!

          //remove itself
          service.GetDataCompleted -= handler;
      }
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request, userState);
}

これで、同時リクエストを作成し、両方のハンドラーが両方のリクエストに対して呼び出された場合でも、正しいリクエストの正しいコードのみがif条件内で実行されます。

使用したくない場合はUserState、ハンドラーが互いにステップオーバーしないように呼び出しを同期する方法がいくつかあります。Tasks以下は、リクエストが次々と発生することを確認する、非ブロッキングの使用方法の1 つです。

Task<GetDataResponse> GetData()
{
  var src = new TaskCompletionSource<GetDataResponse>();     

  var request = new GetDataRequest { someData = "blabla" } ;
  EventHandler handler = null; 
  handler = (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

      src.SetResult(args.Result);

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);

  return src.Task;
}

Task<GetDataResponse> GetData2()
{
  var src = new TaskCompletionSource<GetDataResponse>();

  var request = new GetDataRequest { someData = "blabla2" } ;
  EventHandler handler = null; 

  handler = (sender, args) => 
  {
      // do something different here!

      src.SetResult(args.Result);

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);

  return src.Task;

}

呼び出しメソッドでは、それらが次々と呼び出されるようにします。

GetData().ContinueWith( t => GetData2() );
于 2013-07-30T15:30:18.673 に答える