using 블록의 중간에 반환


196

다음과 같은 것 :

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

나는 그것이 반품 진술에 대한 적절한 장소가 아니라고 생각합니까?

답변:


194

다른 사람들이 일반적으로 지적했듯이 이것은 문제가되지 않습니다.

using 문 중간에 반환하고 추가로 in using 변수를 반환하면 문제가 발생할 수 있습니다. 그러나 다시 말하지만, 반환하지 않고 단순히 변수에 대한 참조를 유지하더라도 문제가 발생할 수 있습니다.

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

나쁘게

Something y;
using ( var x = new Something() ) {
  y = x;
}

1
당신이 언급 한 요점에 대한 질문을 편집하려고했습니다. 감사.
tafa

이것이 왜 나쁜지 이해하도록 도와주세요. 도우미 함수에서 사용중인 Stream을 이미지 처리를 위해 다른 함수로 반환하고 싶습니다. 이 작업을 수행하면 스트림이 삭제되는 것 같습니다.
John Shedletsky

3
@JohnShedletsky이 경우 함수 호출을 사용하여 감싸 야합니다. (Stream x = FuncToReturnStream ()) {...}을 사용하고 FuncToReturnStream 내부를 사용하지 않는 것과 같습니다.
Felix Keil

@JohnShedletsky return명령문이 using모든 코드 경로 에서 블록 의 끝에 액세스 할 수 없기 때문에 확실합니다 . using필요한 경우 객체를 배치 할 수 있도록 블록 끝을 실행해야합니다.
facepalm42

147

완벽하게 괜찮습니다.

당신은 분명히 생각

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

맹목적으로 번역 :

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

어느 쪽이 문제가 될 수 있으며, 그 using진술을 무의미 하게 만들 것입니다 . --- 그것이 그렇게하지 않는 이유입니다 .

컴파일러는 블록을 떠나는 방법에 관계없이 컨트롤이 블록을 떠나기 전에 객체가 배치되도록합니다.


7
나는 분명히 있었다.
tafa

훌륭한 답변 @ James Curran! 그러나 그것이 무엇으로 번역되는지 궁금합니다. 아니면 IL에서만 표현할 수 있습니까? (이전에 읽은 적이 없었습니다).
Bart

1
@Bart-리턴 표현식을 임시 변수로 평가 한 다음 처분을 수행 한 다음 임시 변수를 리턴하는 것으로 생각합니다.
ToolmakerSteve

@ 제임스 커란. 위에서부터 여기까지만, 당신은 배경에서 무슨 일이 일어 났는지 설명했습니다. 많은 감사합니다.
Sercan Timoçin

@Bart 아마 번역 될 것입니다 : try {... your code ...} finally {x.Dispose (); }
Bip901

94

전혀 문제 없습니다. 왜 이것이 잘못되었다고 생각하십니까?

using 문은 try / finally 블록에 대한 구문 설탕이며 Grzenio는 try 블록에서 돌아 오는 것이 좋습니다.

리턴 표현식이 평가되고 finally 블록이 실행 된 후 메소드가 리턴됩니다.


5
James Curran의 답변은 내가 생각한 것을 설명합니다.
tafa

27

중간에 돌아 오는 것처럼 완벽하게 작동합니다. try{}finally{}


18

그것은 완전히 허용됩니다. 사용하여 문으로 IDisposable 개체에 상관없이 배치되지 않습니다 보장합니다.

에서 MSDN :

using 문을 사용하면 객체에서 메서드를 호출하는 동안 예외가 발생하더라도 Dispose가 호출됩니다. try 블록 안에 객체를 넣은 다음 finally 블록에서 Dispose를 호출하여 동일한 결과를 얻을 수 있습니다. 실제로 이것은 using 문이 컴파일러에 의해 번역되는 방식입니다.


14

다음 코드 using는 작동 방식을 보여줍니다 .

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

산출:

't1'이 생성됩니다.
't2'가 생성됩니다.
't3'이 생성됩니다.
't1, t2, t3에서 생성됨'이 생성됩니다.
't3'이 폐기됩니다.
't2'가 배치됩니다.
't1'이 배치됩니다.

처리는 return 문 다음에 그러나 함수가 종료되기 전에 호출됩니다.


1
일부 C #을 예를 들어, 사용자 정의 방식으로 처분 개체주의는 WCF 클라이언트는 "배치 개체에 액세스 할 수 없습니다"위의 반환과 같은 using 문은 제발
OzBob

-4

아마도 이것이 허용되는 것은 100 % 사실이 아닙니다 ...

사용을 중첩하고 중첩 된 것에서 돌아 오는 경우 안전하지 않을 수 있습니다.

이것을 예로 들어 보자.

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

csv로 출력되도록 DataTable을 전달하고있었습니다. 중간에 반환하면 모든 행을 스트림에 쓰지만 출력 된 csv에는 항상 행 (또는 버퍼 크기에 따라 여러 행)이 누락되었습니다. 이것은 무언가가 제대로 닫히지 않았다고 말했습니다.

올바른 방법은 이전의 모든 사용을 올바르게 폐기하는 것입니다.

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.