C #에서 "사용"의 용도는 무엇입니까?


319

사용자 kokos 는 키워드 를 언급하여 C # 의 멋진 숨겨진 기능 질문에 답변했습니다 using. 그것에 대해 자세히 설명해 주시겠습니까? 용도는 using무엇입니까?


RAII 관용구를 지원하는 C # 방식입니다 : hackcraft.net/raii
Nemanja Trifunovic

1
IDispose 인터페이스를 구현 한 객체에 사용할 수 있습니다. 객체가 범위를 벗어날 때를 사용하면 Dispose 메서드가 호출됩니다. 예외가 발생하더라도 Dispose를 호출 할 수 있습니다. finally 절처럼 작동하고 Dispose를 실행합니다.
CharithJ

답변:


480

using명령문 의 이유 는 오브젝트가 범위를 벗어나 자마자 처리되도록하기위한 것이며 명시적인 코드가 필요하지 않습니다.

마찬가지로 C #을 (CodeProject의)에서 '사용'문을 이해 하고 는 IDisposable (마이크로 소프트) 구현하는 객체 사용 , C # 컴파일러의 변환을

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

{ // Limits scope of myRes
    MyResource myRes= new MyResource();
    try
    {
        myRes.DoSomething();
    }
    finally
    {
        // Check for a null resource.
        if (myRes != null)
            // Call the object's Dispose method.
            ((IDisposable)myRes).Dispose();
    }
}

C # 8에는 " using declarations " 라는 새로운 구문이 도입되었습니다 .

using 선언은 using 키워드가 앞에 오는 변수 선언입니다. 선언 된 변수가 둘러싸는 범위의 끝에 배치되어야한다고 컴파일러에 알려줍니다.

따라서 위와 동등한 코드는 다음과 같습니다.

using var myRes = new MyResource();
myRes.DoSomething();

그리고 제어가 포함 범위를 벗어나면 (보통 방법이지만 코드 블록 일 수도 있음) myRes폐기됩니다.


129
물체가 반드시 올바르게 배치되어야하는 것은 아니지만 적시에 배치되는지 여부는 더 중요 합니다. 스트림 및 파일 핸들과 같은 관리되지 않는 리소스를 보유하는 IDisposable을 구현하는 객체는 가비지 수집 중에 Dispose가 호출되도록하는 종료자를 구현합니다. 문제는 GC가 비교적 오랫동안 일어나지 않을 수 있다는 것입니다. using있는지 확인합니다 Dispose당신이 객체를 통해있어 한 번이라고합니다.
John Saunders

1
생성 된 코드는 MyRessource구조체 일 때 약간 다릅니다 . 분명히 nullity에 대한 테스트는 없지만에 대한 권투도 없습니다 IDisposable. 제한된 가상 통화가 발생합니다.
Romain Verdier

4
네임 스페이스를 가져 오는 데 사용을 사용한다고 언급 한 사람이없는 이유는 무엇입니까?
Kyle Delaney

3
두 번째 버전의 코드를 직접 작성하면 결과가 동일하지 않습니다. 를 사용하면 using그 안에 내장 된 변수는 읽기 전용입니다. using명령문 없이 로컬 변수에 대해서는이를 수행 할 방법이 없습니다 .
Massimiliano Kraus

1
@JohnSaunders 또한, 종료자는 호출되지 않을 수 있습니다.
Pablo H

124

많은 사람들이 여전히하기 때문에 :

using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
   //code
}

많은 사람들이 여전히 당신이 할 수 있다는 것을 모른다고 생각합니다.

using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
   //code
}

2
단일 using 문에서 다른 유형의 여러 개체를 사용할 수 있습니까?
Agnel Kurian

12
@AgnelKurian 아니오 : "오류 CS1044 : for, using, fixed 또는 선언문에서 둘 이상의 유형을 사용할 수 없습니다"
David Sykes

10
이 질문에 어떻게 대답합니까?
Liam

실제로 단일 코드 블록 앞에 매번 상태를 사용하여 두 가지를 쓸 수 있다는 것을 몰랐습니다.
kub1x

97

이런 것들 :

using (var conn = new SqlConnection("connection string"))
{
   conn.Open();

    // Execute SQL statement here on the connection you created
}

이것은 SqlConnection명시 적으로 .Close()함수를 호출 할 필요없이 닫 히며 , / / 필요없이 예외가 발생하더라도 발생합니다 .trycatchfinally


1
메서드 내에서 "using"을 사용하고있는 도중에 사용하는 경우 어떻게해야합니까? 무슨 문제라도 있습니까?
francisco_ssb

1
문제가 없습니다. 이 예에서는 블록 return중간에서 연결하더라도 연결이 계속 닫힙니다 using.
Joel Coehoorn

30

사용하여 IDisposable을 호출 할 수 있습니다. 또한 별칭을 별칭으로 사용할 수도 있습니다.

using (SqlConnection cnn = new SqlConnection()) { /*code*/}
using f1 = System.Windows.Forms.Form;

21

의 의미에서

using (var foo = new Bar())
{
  Baz();
}

실제로 try / finally 블록의 속기입니다. 코드와 같습니다.

var foo = new Bar();
try
{
  Baz();
}
finally
{
  foo.Dispose();
}

물론 첫 번째 스 니펫은 두 번째 스 니펫보다 훨씬 간결하며 예외가 발생하더라도 정리로 수행 할 수있는 작업이 많이 있습니다. 이 때문에 Dispose 메서드에서 임의의 코드를 실행할 수있는 Scope라는 클래스가 만들어졌습니다. 예를 들어, 작업을 수행하려고 시도한 후 항상 false로 설정하려는 IsWorking이라는 속성이있는 경우 다음과 같이합니다.

using (new Scope(() => IsWorking = false))
{
  IsWorking = true;
  MundaneYetDangerousWork();
}

우리의 솔루션에 대한 자세한 내용과 여기 에서 우리가 그 솔루션을 도출 한 방법에 대해 읽을 수 있습니다 .


12

Microsoft 설명서에는 using지시문명령문 으로 두 가지 기능 ( https://msdn.microsoft.com/en-us/library/zhdeatwt.aspx ) 이 있다고 명시되어 있습니다. A와 은 다른 답변에서 여기에서 지적 된 바와 같이, 키워드는 기본적으로 처분 할 수있는 범위를 결정하는 문법 설탕이다 는 IDisposable 개체를. A와 지시어 , 그것은 정기적으로 수입 네임 스페이스 및 유형에 사용됩니다. 또한 지시자로, 당신은 만들 수 있습니다 별칭 이 책에서 지적 밖으로로서, 네임 스페이스 및 유형을 "간단히 말해서 C # 5.0 : 확실한 가이드"( http://www.amazon.com/5-0-Nutshell-The-을 확정 참조 전자 책 / dp / B008E6I1K8), 조셉과 벤 알바 하리 한 가지 예 :

namespace HelloWorld
{
    using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
    public class Startup
    {
        public static AppFunc OrderEvents() 
        {
            AppFunc appFunc = (IDictionary<DateTime, string> events) =>
            {
                if ((events != null) && (events.Count > 0))
                {
                    List<string> result = events.OrderBy(ev => ev.Key)
                        .Select(ev => ev.Value)
                        .ToList();
                    return result;
                }
                throw new ArgumentException("Event dictionary is null or empty.");
            };
            return appFunc;
        }
    }
}

이 관행을 남용하면 코드의 명확성이 손상 될 수 있기 때문에 현명하게 채택해야합니다. DotNetPearls ( http://www.dotnetperls.com/using-alias ) 에는 장단점을 언급하는 C # 별칭에 대한 좋은 설명이 있습니다 .


4
거짓말하지 않을 것 : 나는 별칭 도구로 사용하는 것을 싫어 합니다 using. 코드를 읽을 때 혼란 스럽습니다. 이미 System.Collections존재하고 IEnumerable<T>클래스 가 있음을 이미 알고 있습니다 . 별명을 사용하여 그것을 다른 것으로 부르면 나를 위해 난독 화합니다. 내가 볼 using FooCollection = IEnumerable<Foo>나중에 개발자가 코드를 읽고, 생각하게하는 방법으로 "지옥이 무엇 FooCollection이며 왜위한 클래스는 곳이 없다?" 나는 그것을 사용하지 않으며 사용을 권장하지 않습니다. 그러나 그것은 단지 나일지도 모른다.
Ari Roth

1
부록 : 델리게이트를 정의하는 데 사용하는 예와 같이 가끔 사용하는 경우도 있음을 인정합니다. 그러나 나는 그것들이 상대적으로 드물다고 주장합니다.
Ari Roth

10

과거에는 입력 및 출력 스트림으로 작업하는 데 많이 사용했습니다. 그것들을 멋지게 중첩시킬 수 있으며 일반적으로 (dispose를 자동으로 호출하여) 일반적으로 발생하는 많은 잠재적 문제를 제거합니다. 예를 들면 다음과 같습니다.

        using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
        {
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (System.IO.StreamReader sr = new StreamReader(bs))
                {
                    string output = sr.ReadToEnd();
                }
            }
        }

8

내가 놀란 작은 것을 추가하는 것은 나타나지 않았습니다. (내 의견으로는) 사용의 가장 흥미로운 특징은 사용 블록을 종료하는 방법이 중요하지 않으며 항상 객체를 처분한다는 것입니다. 여기에는 반품 및 예외가 포함됩니다.

using (var db = new DbContext())
{
    if(db.State == State.Closed) throw new Exception("Database connection is closed.");
    return db.Something.ToList();
}

예외가 발생하거나 목록이 반환되는지는 중요하지 않습니다. DbContext 객체는 항상 폐기됩니다.


6

모달 대화 상자를 인스턴스화 할 때 사용하는 또 다른 용도가 많습니다.

Using frm as new Form1

Form1.ShowDialog

' do stuff here

End Using

1
frm.ShowDialog을 의미 했습니까?
UuDdLrLrSs

5

이 유형의 로컬 변수를 사용할 때 결론적으로, 구현은 IDisposable, 항상 예외없이 사용 using1 .

비 로컬 IDisposable변수 를 사용하는 경우 항상 IDisposable패턴을 구현하십시오 .

두 가지 간단한 규칙, 예외 없음 1 . 그렇지 않으면 리소스 누출을 방지하는 것이 실제로 고통 스럽습니다.


1) : 예외를 처리 할 때는 예외입니다. 그러면 블록 Dispose에서 명시 적으로 호출하는 코드가 줄어 듭니다 finally.


5

다음 예제를 통해 별명 네임 스페이스를 사용할 수 있습니다.

using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;

이를 사용하여 별칭 지시어 라고합니다. 예를 들어 코드에서 명확하게 설명하려는 경우 긴 참조를 숨기는 데 사용할 수 있습니다.

LegacyEntities.Account

대신에

CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account

또는 단순히

Account   // It is not obvious this is a legacy entity

4

흥미롭게도 Rhino Mocks가 사용하는 방식과 같은 다른 흥미로운 것들에 대해 using / IDisposable 패턴을 사용할 수도 있습니다. 기본적으로 컴파일러는 항상 "사용 된"객체에서 .Dispose를 호출 한다는 사실을 이용할 수 있습니다 . 특정 작업 후 시작해야하는 작업 (확실한 시작 및 종료 기능이있는 작업)이있는 경우 생성자에서 작업을 시작한 다음 Dispose 메서드에서 완료하는 IDisposable 클래스를 만들 수 있습니다.

이를 통해 정말 멋진 구문을 사용하여 해당 작업의 명시 적 시작과 끝을 나타낼 수 있습니다. 이것은 System.Transactions 기능도 작동합니다.


3

ADO.NET을 사용하는 경우 연결 개체 또는 리더 개체와 같은 작업에 키 워크를 사용할 수 있습니다. 이렇게하면 코드 블록이 완료되면 자동으로 연결이 삭제됩니다.


2
코드 블록을 완료 할 필요조차 없다고 덧붙입니다. using 블록은 처리되지 않은 예외가 발생하더라도 리소스를 처리합니다.
harpo

그냥 추가로 확실히 수집기는 당신이 원하는 당신의 할당을 담당 쓰레기를 만드는 대신 때 그 일을하는 방법, 명확하게 그것을 원한다.
moswald


3
public class ClassA:IDisposable

{
   #region IDisposable Members        
    public void Dispose()
    {            
        GC.SuppressFinalize(this);
    }
    #endregion
}

public void fn_Data()

    {
     using (ClassA ObjectName = new ClassA())
            {
                //use objectName 
            }
    }

2

using 은 사용한 후에 폐기하려는 리소스가있을 때 사용됩니다.

예를 들어, 파일 리소스를 할당하고 약간의 읽기 또는 쓰기를 위해 한 섹션의 코드에서만 사용해야하는 경우 사용하면 파일 리소스를 처리하는 즉시 처리하는 데 도움이됩니다.

사용중인 리소스가 제대로 작동하려면 IDisposable을 구현해야합니다.

예:

using (File file = new File (parameters))
{
    *code to do stuff with the file*
}

1

using 키워드는 객체의 범위를 정의한 다음 범위가 완료되면 객체를 삭제합니다. 예를 들어.

using (Font font2 = new Font("Arial", 10.0f))
{
    // use font2
}

키워드를 사용하는 C #에 대한 MSDN 기사는 여기 를 참조 하십시오 .


1

매우 중요하지는 않지만 사용은 자원을 즉시 변경하는 데 사용될 수도 있습니다. 예, 앞에서 언급했듯이 일회용이지만, 특히 실행하는 동안 다른 리소스와 일치하지 않는 리소스를 원하지 않을 수 있습니다. 따라서 다른 곳을 방해하지 않도록 폐기하십시오.


1

(사과를 나는 시간에 단어 '가비지 수집을'사용 안) 아래의 의견 덕분에, 나는 조금 업이 게시물을 정리합니다 :
당신이 사용하는 사용하는 경우, 그것은 개체의 폐기 () 메소드를 호출 사용 범위의 끝에서. 따라서 Dispose () 메서드에 상당히 훌륭한 정리 코드가있을 수 있습니다.
IDisposable을 구현하는 경우 Dispose () 구현에서 GC.SuppressFinalize ()를 호출해야합니다. 적어도 이미 Dispose () d 한 경우 리소스 낭비가 될 것입니다.


간접적 인 효과가 있습니다. 객체를 명시 적으로 폐기 했으므로 마무리 할 필요가 없으므로 GC를 더 일찍 수행 할 수 있습니다.
Kent Boogaart

1

물체가 즉시 폐기되는 합리적인 사용의 또 다른 예 :

using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString)) 
{
    while (myReader.Read()) 
    {
        MyObject theObject = new MyObject();
        theObject.PublicProperty = myReader.GetString(0);
        myCollection.Add(theObject);
    }
}

1

중괄호 밖의 모든 것은 폐기되므로 사용하지 않을 경우 폐기하는 것이 좋습니다. SqlDataAdapter 개체가 있고 응용 프로그램 수명주기에서 한 번만 사용하고 하나의 데이터 집합 만 채우고 더 이상 필요하지 않은 경우 코드를 사용할 수 있기 때문입니다.

using(SqlDataAdapter adapter_object = new SqlDataAdapter(sql_command_parameter))
{
   // do stuff
} // here adapter_object is disposed automatically

1

using 문은 IDisposable 객체를 올바르게 사용하기위한 편리한 메커니즘을 제공합니다. 일반적으로 IDisposable 객체를 사용할 때는 using 문에서 선언하고 인스턴스화해야합니다. using 문은 올바른 방식으로 개체에서 Dispose 메서드를 호출하며, 앞에서 설명한대로 사용하면 Dispose가 호출 되 자마자 개체 자체가 범위를 벗어납니다. using 블록 내에서 개체는 읽기 전용이므로 수정하거나 재 할당 할 수 없습니다.

여기에서 온다 : here


1

나에게 "using"이라는 이름은 약간 혼란 스럽습니다. 왜냐하면 네임 스페이스를 가져 오는 지시문이나 오류 처리를 위해 명령문 (여기에서 설명한 것과 같은 명령문) 일 수 있기 때문입니다.

오류 처리의 다른 이름은 좋았으며 어쩌면 더 분명한 이름 일 것입니다.


1

예를 들어 범위를 만드는 데 사용할 수도 있습니다.

class LoggerScope:IDisposable {
   static ThreadLocal<LoggerScope> threadScope = 
        new ThreadLocal<LoggerScope>();
   private LoggerScope previous;

   public static LoggerScope Current=> threadScope.Value;

   public bool WithTime{get;}

   public LoggerScope(bool withTime){
       previous = threadScope.Value;
       threadScope.Value = this;
       WithTime=withTime;
   }

   public void Dispose(){
       threadScope.Value = previous;
   }
}


class Program {
   public static void Main(params string[] args){
       new Program().Run();
   }

   public void Run(){
      log("something happend!");
      using(new LoggerScope(false)){
          log("the quick brown fox jumps over the lazy dog!");
          using(new LoggerScope(true)){
              log("nested scope!");
          }
      }
   }

   void log(string message){
      if(LoggerScope.Current!=null){
          Console.WriteLine(message);
          if(LoggerScope.Current.WithTime){
             Console.WriteLine(DateTime.Now);
          }
      }
   }

}

1

using 문은 .NET에 using 블록에 지정된 개체가 더 이상 필요하지 않으면 해제하도록 지시합니다. 따라서 System.IO 유형과 같이 클래스를 정리해야하는 클래스에는 'using'블록을 사용해야합니다.


1

usingC # 에서 키워드는 다음과 같이 두 가지 용도 로 사용됩니다.

  1. 지침으로

    일반적으로 using키워드를 사용하여 코드 숨김 및 클래스 파일에 네임 스페이스를 추가합니다. 그런 다음 현재 페이지에서 모든 클래스, 인터페이스 및 추상 클래스와 해당 메소드 및 특성을 사용할 수 있습니다.

    예:

    using System.IO;
  2. 성명서

    usingC # 에서 키워드 를 사용하는 또 다른 방법 입니다. 가비지 콜렉션에서 성능을 향상시키는 데 중요한 역할을합니다.

    using문은 객체를 만들거나 메서드, 속성 등을 호출 할 때 예외가 발생하더라도 Dispose ()가 호출되도록합니다. Dispose ()는 IDisposable 인터페이스에 있으며 사용자 지정 가비지 수집을 구현하는 데 도움이되는 메서드입니다. 즉, 데이터베이스 작업 (삽입, 업데이트, 삭제)을 수행하고 있지만 예외가 발생하면 using 문이 자동으로 연결을 닫습니다. 연결 Close () 메소드를 명시 적으로 호출 할 필요가 없습니다.

    또 다른 중요한 요소는 연결 풀링에 도움이된다는 것입니다. .NET의 연결 풀링은 데이터베이스 연결을 여러 번 닫는 것을 방지합니다. 나중에 사용할 수 있도록 연결 개체를 풀로 보냅니다 (다음 데이터베이스 호출). 다음에 응용 프로그램에서 데이터베이스 연결을 호출하면 연결 풀이 풀에서 사용 가능한 개체를 가져옵니다. 따라서 응용 프로그램의 성능을 향상시키는 데 도움이됩니다. 따라서 using 문을 사용하면 컨트롤러가 자동으로 객체를 연결 풀로 전송하므로 Close () 및 Dispose () 메서드를 명시 적으로 호출 할 필요가 없습니다.

    try-catch 블록을 사용하여 using 문과 동일한 작업을 수행하고 finally 블록 내에서 Dispose ()를 명시 적으로 호출 할 수 있습니다. 그러나 using 문은 코드를 더 깨끗하고 우아하게 만들기 위해 자동으로 호출을 수행합니다. using 블록 내에서 개체는 읽기 전용이므로 수정하거나 재 할당 할 수 없습니다.

    예:

    string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
    
    using (SqlConnection conn = new SqlConnection(connString))
    {
          SqlCommand cmd = conn.CreateCommand();
          cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
          conn.Open();
          using (SqlDataReader dr = cmd.ExecuteReader())
          {
             while (dr.Read())
             Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
          }
    }

앞의 코드에서 나는 어떤 연결도 닫지 않았다. 자동으로 닫힙니다. using문 인해 자동) conn.Close을 (호출 using문 ( using (SqlConnection conn = new SqlConnection(connString))와 SqlDataReader 개체 개체에 대한 동일. 또한 예외가 발생하면 연결이 자동으로 닫힙니다.

자세한 내용 은 C #에서 사용 및 사용의 중요성을 참조하십시오 .



-1

명령문으로 사용하면 지정된 오브젝트에서 처분을 자동으로 호출합니다. 객체는 IDisposable 인터페이스를 구현해야합니다. 동일한 유형 인 한 명령문에서 여러 오브젝트를 사용할 수 있습니다.

CLR은 코드를 MSIL로 변환합니다. using 문은 try 및 finally 블록으로 변환됩니다. 이것이 using 문이 IL에서 표현되는 방식입니다. using 문은 획득, 사용 및 폐기의 세 부분으로 번역됩니다. 자원을 먼저 확보 한 후 사용법은 finally 절과 함께 try 문으로 묶습니다. 그런 다음 객체는 finally 절에 배치됩니다.


-3

사용 절은 특정 변수의 범위를 정의하는 데 사용됩니다. 예를 들면 다음과 같습니다.

     Using(SqlConnection conn=new SqlConnection(ConnectionString)
            {
                Conn.Open()
            // Execute sql statements here.
           // You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
            }

이것은 객체를 폐기하는 데 사용하는 사람을 그리워 할 수 있습니다. 변수의 범위를 제한하려는 경우 중첩 코드 블록을 사용할 수 있습니다. public static void Main (params string [] args) {{// nested code block}}
luiseduardohd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.