{} 문을 사용하여 내부에서 return을 호출하는 것이 좋은 방법입니까?


93

블록 return내부 를 호출 하는 것이 안전하고 좋은 접근 방식인지 알고 싶습니다 using.

예를 들어.

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것이다 "휴식"범위 - 객체가 예상대로 배치 얻을 것이다, 그래서
샤이

4
귀하 scope.Complete()가 제공 한 샘플로 귀하의 전화가 결코 히트하지 않으므로 트랜잭션이 항상 롤백됩니다.
Andy

usingdispose()호출 여부에 관계없이 를 반환하면이 using블록을 포함하는 함수 가 반환되고 그에 속한 모든 것이 고아가됩니다. 따라서 scope"에 의해 using"(다른 사람들이 설명했듯이) 폐기되지 않았 더라도 함수가 종료 되었기 때문에 어쨌든 폐기 될 것입니다. C #에 goto진술 이 있다면 -아직 웃었습니까? 좋은-반환하는 대신에 반환 goto하지 않고 닫는 중괄호 뒤에 할 수 있습니다. 논리적으로 scope는 여전히 폐기되지만 gotoC #을 입력 했으므로 해당 단계에서 논리에 관심이있는 사람은 누구입니까?
Superbest


답변:


146

return내부 를 호출하는 것은 완벽하게 안전 합니다.usingusing 블록은 블록 일 뿐이므로 블록try/finally .

위의 예에서 return 후 true범위가 삭제되고 값이 반환됩니다. return false, 그리고 scope.Complete()의지 하지 전화 . Dispose그러나 finally 블록 안에 있으므로 관계없이 호출됩니다.

코드는 기본적으로 다음과 동일합니다 (이해하기 쉽게 만들 수있는 경우).

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

using 블록을 반환하는 것은 괜찮지 만 TransactionScope의 경우 사용 문 자체에 문제가 발생할 수 있습니다 : blogs.msdn.com/b/florinlazar/archive/2008/05/05/8459994.aspx
thewhiteambit 2015 년

내 경험상 이것은 SQL Server CLR 어셈블리에서 작동하지 않습니다. MemoryStream 개체를 참조하는 SqlXml 필드가 포함 된 UDF에 대한 결과를 반환해야하는 경우. " Cannot access a deleted object "및 " Invalid attempt to call Read when the stream is closed. "가 표시되므로 누수 코드를 작성하고이 시나리오에서 using-statement를 잊어 버립니다. . :( 내 유일한 희망은 그것은 독특한 시나리오 년대 이러한 개체의 폐기를 처리 할 SQL CLR,하지만 난 공유하고자합니다.
MikeTeeVee

1
@MikeTeeVee는 - 클리너 솔루션 (a)는 않는 발신자가 하나 있습니다 using, 예를 들어 using (var callersVar = MyFunc(..)) .., 대신 스트림을 주어 통해 폐쇄에 대한 책임이있다 나는 발신자를 의미 - 사용하여 내부 "Func라고"을있는의를 using또는 명시 적으로, 또는 (b) MyFunc 가 필요한 모든 정보를 다른 개체로 추출 하도록하여 안전하게 다시 전달할 수 있습니다. 그런 다음 기본 데이터 개체 또는 스트림을 using. 새는 코드를 작성할 필요가 없습니다.
ToolmakerSteve

6

괜찮습니다. finally절 (절의 닫는 중괄호 using가 내부에서 수행하는 작업)은 범위가 남아있을 때 항상 실행됩니다.

그러나 이것은 finally 블록에있는 문에만 해당됩니다 (를 사용할 때 명시 적으로 설정할 수 없음 using). 따라서 귀하의 예제에서는 scope.Complete()호출되지 않습니다 (컴파일러가 도달 할 수없는 코드에 대해 경고 할 것으로 예상합니다).


2

일반적으로 좋은 접근 방식입니다. 그러나 귀하의 경우에는 전화하기 전에 돌아 오면scope.Complete() TransactionScope를 폐기합니다. 디자인에 따라 다릅니다.

따라서이 샘플에서는 Complete ()가 호출되지 않고 범위가 IDisposable 인터페이스를 상속한다고 가정하여 삭제됩니다.


IDisposable을 구현하거나 컴파일되지 않을 것입니다.
Chriseyre2000 2012-08-02

2

scope.Complete는 확실히 전에 호출되어야 return합니다. 컴파일러는 경고를 표시하고이 코드는 호출되지 않습니다.

return그 자체에 관해서 는-예, 내부 using진술 이라고 부르는 것이 안전 합니다. 사용은 씬 뒤에서 try-finally 블록으로 번역되고 finally 블록은 확실히 실행됩니다.


1

제공 한 예에 문제가 있습니다. scope.Complete()호출되지 않습니다. 둘째, return문 안에 using문 을 사용하는 것은 좋은 습관이 아닙니다 . 다음을 참조하십시오.

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

이 간단한 예에서 요점은 다음과 같습니다. 의 가치scope문 사용이 완료되면 null이됩니다.

따라서 문을 사용하여 내부로 반환하지 않는 것이 좋습니다.


1
'반환 범위'가 무의미하다고해서 return 문이 잘못되었음을 의미하지는 않습니다.
Preet Sangha

모범 사례를 사용하지 않는다고해서 잘못된 일을 한 것은 아닙니다. 예상치 못한 결과를 초래할 수 있으므로 피하는 것이 가장 좋습니다.
daryal

1
의 값은 scopenull이 아닙니다. 발생하는 유일한 것은 해당 Dispose()인스턴스에서 호출 된 것이므로 인스턴스 더 이상 사용 해서는 안됩니다 (하지만 null이 아니므로 시도하고 사용하는 데 방해가되는 것은 없습니다. 폐기 된 객체, 비록 이것이 실제로 일회용 객체의 부적절한 사용 임에도 불구하고).
Lucero

Lucero는 아주 정확합니다. 폐기 가능한 개체는 삭제 된 후 null이 아닙니다. IsDisposed 속성은 true이지만 null에 대해 확인하면 false가되고 해당 개체에 return scope대한 참조를 반환 합니다. 이렇게하면 반환시 해당 참조를 할당하면 GC가 삭제 된 개체를 정리하지 못합니다.
ThunderGr

1

scope.Complete()이 호출 되는지 확인하려면 try/finally. 는 dispose당신이 그것을 포장이 있기 때문에라고 using대안입니다 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.