3

usingステートメントの適切な範囲について、同僚と口論になっています。これが問題の方法です。

public Guid IsServerReachable()
{
  try
  {
    WhoAmIResponse whoAmI;
    using (OrganizationServiceProxy service = GetService())
      whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
    return whoAmI.UserId;
  }
  catch { return Guid.Empty; }
}

私たちの 1 人は、usingステートメントにwhyAmIの宣言を含める必要があると主張し、もう 1 人は、using 化する必要があるのはサービスインスタンスのみであると主張します。どちらが私の理論かはわかりませんが、明らかに間違っているのは 1 つです。どれの?

4

5 に答える 5

6

どちらも正しいです。私はこれを書く傾向があります:

public Guid IsServerReachable()
{
    try
    {
        using (OrganizationServiceProxy service = GetService())
        {
            WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
            return whoAmI.UserId;
        }
    }
    catch { return Guid.Empty; }
}

これは、 が破棄されるかどうかには影響しません。whoAmI自動的に破棄されるのは だけですservice

WhoAmIResponseも であった場合IDisposable、両方を自動的に解放するには、次のように記述する必要があります。

    using (OrganizationServiceProxy service = GetService())
    using (WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse)
        return whoAmI.UserId;
于 2013-03-20T14:19:29.320 に答える
3

この場合、の宣言はwhoAmIパフォーマンス/スコープの点で実際には何の違いもありません。結局のところ、のプロパティアクセスwhoAmI.UserIdもに含まれている必要がありますusing。ILの観点から見ると、この2つの機能の違いは、OrganizationalServiceProxy.Disposeメソッドが呼び出される順序と、にWhoAmIResponse.UserIdアクセスするタイミングだけです。

(編集:デフォルト値を返すための処理方法に実際の問題はないと思います。それtry/catchは質問の一部ではないようですので、これも省略されています)

投稿されたコード(ILを明確にするために簡略化):

public Guid IsServerReachableOutsideUsingScope()
{
    WhoAmIResponse whoAmI;
    using(var service = new Service())
        whoAmI = service.Execute();
    return whoAmI.UserId;
}

次のILの結果:

IL_0000:  newobj      UserQuery+Service..ctor
IL_0005:  stloc.1     // service
IL_0006:  ldloc.1     // service
IL_0007:  callvirt    UserQuery+Service.Execute
IL_000C:  stloc.0     // whoAmI
IL_000D:  leave.s     IL_0019
IL_000F:  ldloc.1     // service
IL_0010:  brfalse.s   IL_0018
IL_0012:  ldloc.1     // service
IL_0013:  callvirt    System.IDisposable.Dispose
IL_0018:  endfinally  
IL_0019:  ldloc.0     // whoAmI
IL_001A:  callvirt    UserQuery+WhoAmIResponse.get_UserId
IL_001F:  ret         

usingブロック内のすべてを宣言するのに対して:

public Guid IsServerReachableWithinUsingScope()
{
    using(var service = new Service())
    {
        WhoAmIResponse whoAmI = service.Execute();
        return whoAmI.UserId;
    }
}

ILを生成します:

IL_0000:  newobj      UserQuery+Service..ctor
IL_0005:  stloc.0     // service
IL_0006:  ldloc.0     // service
IL_0007:  callvirt    UserQuery+Service.Execute
IL_000C:  stloc.1     // whoAmI
IL_000D:  ldloc.1     // whoAmI
IL_000E:  callvirt    UserQuery+WhoAmIResponse.get_UserId
IL_0013:  stloc.2     // CS$1$0000
IL_0014:  leave.s     IL_0020
IL_0016:  ldloc.0     // service
IL_0017:  brfalse.s   IL_001F
IL_0019:  ldloc.0     // service
IL_001A:  callvirt    System.IDisposable.Dispose
IL_001F:  endfinally  
IL_0020:  ldloc.2     // CS$1$0000
IL_0021:  ret         

プロパティにアクセスする前にサービスを破棄しないことが重要な場合(たとえば、NHibernateの遅延ロードされたコレクションのコンテキストで)、順序は間違いなく重要です。それが問題ではない場合、最大の問題はあなたとあなたのチームが最も気にかけていることです。呼び出しの混合と一致を気にせず、中かっこがあるものとないものがある場合は、持っているものを続行します。using

おそらくWhoAmIResponse.UserId、アクセスに副作用がある場合に考慮すべきことは、例外処理の順序です。サービスの呼び出しが例外をスローした場合、元のコード( )では、プロパティにアクセスしたことがないため、副作用が実行されることはありません。コードの2番目のブロック( )では、プロパティを使用することによる副作用にアクセスして実行し、次に例外をスローするを実行します。DisposeIsServerReachableOutsideUsingScopeIsServerReachableWithinUsingScopeUserIdDispose

これらはかなりまれなケースです(編集:get-accessの副作用とDispose()例外のスローの両方が悪い習慣と見なされることに注意してください)。ここでそれが当てはまる場合は、これらを正しく検討する必要がありますこれらが問題ではない場合(副作用がなく、アクセス/廃棄の順序を気にしない)、長期的にはあなたとあなたのチームがより保守可能/読みやすいと感じるものを使用してください。

于 2013-03-20T14:53:43.097 に答える
1

ステートメントには、ステートメントのusing終了時に破棄されるオブジェクトの宣言が含まれている必要があります。OrganizationServiceProxyあなたのコードは、実装して実装IDisposableWhoAmIResponseていない限り正しいです。

疑問がある場合は、通常、using ブロックを try-finally ブロックとして書き直すと便利です。

OrganizationServiceProxy service = GetService();
try {
   whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
} finally {
    service.Dispose();
}
于 2013-03-20T14:15:51.120 に答える
1

usingステートメントの範囲をできるだけ小さくするのがベスト プラクティスです。OrganizationServiceProxyメソッドの実行時に返されたオブジェクトが破棄されない限りDispose、指定されたスコープは完全に受け入れられます。

于 2013-03-20T14:20:12.427 に答える
0
using (OrganizationServiceProxy service = GetService())
    whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;

以下と同等になります。

OrganizationServiceProxy service = GetService();
try
{
    whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
}
finally
{
    if (myRes!= null)
        // Call the object's Dispose method.
        ((IDisposable)service).Dispose();
}
于 2013-03-20T14:16:53.950 に答える