{}ステートメントを使用して内部でreturnを呼び出すのは良い方法ですか?


90

returnusingブロック内で呼び出すことが安全/良いアプローチであることを知りたいだけです。

例のために。

using(var scope = new TransactionScope())
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}

私たちは、最後に最も中かっこdispose()が取り消されることを知ってい ます。しかし、上記の場合returnは、指定されたスコープ(AFAIK)の外にコントロールをジャンプするので...

  1. scope.Complete()は呼ばれますか?
  2. スコープのdispose()メソッドについても同様です。

1
一度using{}スコープが終わって、関連するオブジェクトが配置され、取得return範囲だろう「休憩」を-予想通りのオブジェクトが配置されますので、
シャイ

2
scope.Complete()提供されたサンプルでコールがヒットすることはないため、トランザクションは常にロールバックされることに注意してください。
アンディ

かかわらずかどうかのusingのはdispose()あなたが戻ったときに、呼ばれ、この含む機能usingブロックが戻ってきたし、それに属するすべてのものが孤立します。したがってscope、「によってusing」(他の人が説明したように)破棄されていなくても、関数が終了したため、とにかく破棄されます。C#にgoto発言があった場合-もう笑っていますか?じゃあ、戻るのではなくgoto、閉じ中括弧の後で、戻らないで。論理的にscopeは、まだ破棄されますがgoto、C#に入れただけなので、その段階で誰がロジックを気にしますか。
スーパーベスト2012


回答:


142

usingブロックは単なるブロックなので、ブロックreturn内で呼び出すのは完全に安全です。usingtry/finally

上記のreturn後の例trueでは、スコープが破棄され、値が返されます。なりません呼び出されます。ただし、finallyブロック内にあるため、呼び出されます。return falsescope.Complete()Dispose

あなたのコードは基本的にこれと同じです(それが理解しやすくする場合):

var scope = new TransactionScope())
try
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}
finally
{
  if( scope != null) 
    ((IDisposable)scope).Dispose();
}

トランザクションをコミットする方法がないため、トランザクションは決してコミットしないことに注意してくださいscope.Complete()


13
呼び出されることを明確にする必要Dispose があります。OPがで何が起こるかを知らない場合、using彼は何が起こるかを知らない可能性がありfinallyます。
Konrad Rudolph

returnを使用してusingブロックを残してもかまいませんが、TransactionScopeの場合は、usingステートメント自体で問題が発生する可能性があります。blogs.msdn.com
thewhiteambit 2015年

私の経験では、これはSQL Server CLRアセンブリでは機能しません。MemoryStreamオブジェクトを参照しているSqlXmlフィールドを含むUDFの結果を返す必要がある場合。私が取得する「破棄されたオブジェクトにアクセスすることはできませんし、」「ストリームが閉じられたときに読むを呼び出すための無効な試みを。」、私は漏れやすいコードを書くと、このシナリオで使用して文を見送ることを強制していますので。:(私の唯一の希望は、それがユニークなシナリオだSQL CLRは、これらのオブジェクトの処分を処理しますが、私は共有したいと思っていた。。
MikeTeeVee

1
@MikeTeeVee-よりクリーンなソリューションは、(a)呼び出し元にを実行させるusing(たとえばusing (var callersVar = MyFunc(..)) ..、「MyFunc」内で使用するのではなく) -呼び出し元にストリームが与えられ、それを介してusingまたは明示的に閉じる責任がある、または(b) MyFuncに必要な情報を他のオブジェクトに抽出させ、それを安全に戻すことができますusing。その後、基になるデータオブジェクトまたはストリームをによって破棄できます。漏洩コードを書く必要はありません。
ToolmakerSteve 2017年

6

それfinallyusing問題ありません- 句(これは、句の閉じ中括弧がフードの下で行うことです)は、スコープに関係なく、常に実行されます。

ただし、これは、finallyブロック(を使用するときに明示的に設定することはできません)内のステートメントにのみ当てはまりますusing。したがって、あなたの例でscope.Complete()は、決して呼び出されません(ただし、到達できないコードについてコンパイラが警告することを期待しています)。


2

一般的に、これは良いアプローチです。しかし、あなたの場合、を呼び出す前に戻ると、scope.Complete()単にTransactionScopeが破棄されます。あなたのデザインに依存します。

したがって、このサンプルでは、​​Complete()は呼び出されず、IDisposableインターフェイスを継承していると想定して、スコープが破棄されます。


IDisposableを実装するか、Wontコンパイルを使用する必要があります。
Chriseyre2000 2012

2

scope.Completeは必ず前に呼び出す必要がありますreturn。コンパイラーは警告を表示し、このコードは呼び出されません。

returnそれ自体について-はい、usingステートメント内で呼び出すのは安全です。を使用すると、舞台裏で最後にブロックするように変換され、最後にブロックが確実に実行されます。


1

あなたが提供した例では、問題があります。scope.Complete()呼び出されることはありません。次に、returnステートメント内でusingステートメントを使用することはお勧めできません。以下を参照してください。

using(var scope = new TransactionScope())
{
    //have some logic here
    return scope;      
}

この単純な例では、ポイントはそれです。scopeステートメントの使用が終了すると、の値はnullになります。

したがって、ステートメントを使用して内部に戻ることはお勧めしません。


1
「return scope」が無意味だからといって、returnステートメントが間違っていることを意味するものではありません。
Preet Sangha 2012

ベストプラクティスを使用しないからといって、何か間違ったことをしたわけではありません。予期せぬ結果を招く可能性があるため、回避することをお勧めします。
12

1
の値はscopenullにはなりません-発生するのはそのDispose()インスタンスで呼び出されることだけなので、インスタンスもう使用されません(ただし、nullではなく、試して使用するのを妨げるものはありません)これは確かに使い捨てオブジェクトの不適切な使用ですが、廃棄オブジェクト)。
Lucero

ルセロは正解です。破棄されたオブジェクトは破棄されてもnullではありません。そのIsDisposedプロパティはtrueですが、nullに対してチェックするとfalseになりreturn scopeそのオブジェクトへの参照を返します。このように、戻り時にその参照を割り当てると、GCが破棄されたオブジェクトをクリーンアップできなくなります。
ThunderGr 2013年

1

scope.Complete()が呼び出されることを確認するには、でラップしtry/finallyます。これdisposeusing、代替try/finallyブロックであるでラップしているために呼び出されます。

using(var scope = new TransactionScope())
{
  try
  {
  // my core logic
  return true; // if condition met else
  return false;
  }
  finally
  {
   scope.Complete();
  }
}

私はあなたが言いたいと思うと思います。:)

0

この例では、scope.Complete()は実行されません。ただし、returnコマンドは、スタックに割り当てられているすべてのものをクリーンアップします。GCは参照されていないものすべてを処理します。したがって、GCで取得できないオブジェクトがない限り、問題はありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.