다음을 통해 공유


"패턴 기반 using" 및 "using 선언"

메모

이 문서는 기능 사양입니다. 사양은 기능의 디자인 문서 역할을 합니다. 여기에는 기능 디자인 및 개발 중에 필요한 정보와 함께 제안된 사양 변경 내용이 포함됩니다. 이러한 문서는 제안된 사양 변경이 완료되고 현재 ECMA 사양에 통합될 때까지 게시됩니다.

기능 사양과 완료된 구현 간에 약간의 불일치가 있을 수 있습니다. 관련 언어 디자인 모임(LDM) 노트에 이러한 차이가 기록됩니다.

사양문서에서는 C# 언어 표준으로 기능 사양 항목을 채택하는 프로세스에 대해 자세히 알아볼 수 있습니다.

챔피언 이슈: https://github.com/dotnet/csharplang/issues/114

요약

이 언어는 리소스 관리를 더 간단하게 하기 위해 using 문 주위에 두 가지 새로운 기능을 추가합니다. usingIDisposable 외에 삭제 가능한 패턴을 인식하고 언어에 using 선언을 추가해야 합니다.

동기

using 문은 오늘날 리소스 관리를 위한 효과적인 도구이지만 상당한 절차가 필요합니다. 관리할 리소스가 많은 메서드는 일련의 using 문으로 구문적으로 복잡해질 수 있습니다. 이 구문 부담은 대부분의 코딩 스타일 지침에 이 시나리오의 중괄호에 대한 예외가 명시적으로 있을 정도로 충분합니다.

using 선언은 여기에서 대부분의 의식을 제거하고 리소스 관리 블록을 포함하는 다른 언어와 동등한 C#을 가져옵니다. 또한 패턴 기반 using는 개발자가 사용할 수 있는 형식 집합을 확장할 수 있게 합니다. 많은 경우, using 문에서 값을 사용하기 위한 목적만으로 존재하는 래퍼 형식을 만들 필요가 없어집니다.

이러한 기능을 함께 사용하면 개발자가 using 적용할 수 있는 시나리오를 단순화하고 확장할 수 있습니다.

상세 디자인

using 디렉티브 선언

언어를 사용하면 using 지역 변수 선언에 추가할 수 있습니다. 이러한 선언은 동일한 위치에 있는 using 문에서 변수를 선언하는 것과 동일한 효과를 갖습니다.

if (...) 
{ 
   using FileStream f = new FileStream(@"C:\source\using.md");
   // statements
}

// Equivalent to 
if (...) 
{ 
   using (FileStream f = new FileStream(@"C:\source\using.md")) 
   {
    // statements
   }
}

using 로컬의 수명은 선언된 범위의 끝까지 확장됩니다. using 지역 주민은 선언된 역순으로 삭제됩니다.

{ 
    using var f1 = new FileStream("...");
    using var f2 = new FileStream("...");
    using var f3 = new FileStream("...");
    ...
    // Dispose f3
    // Dispose f2 
    // Dispose f1
}

goto이나 using 선언을 포함한 다른 제어 흐름 구문과 관련하여 제한이 없습니다. 대신 코드는 해당하는 using 문과 마찬가지로 작동합니다.

{
    using var f1 = new FileStream("...");
  target:
    using var f2 = new FileStream("...");
    if (someCondition) 
    {
        // Causes f2 to be disposed but has no effect on f1
        goto target;
    }
}

using 로컬 선언에 선언된 로컬은 암묵적으로 읽기 전용이 됩니다. 이는 using 문에 선언된 지역 변수의 동작과 일치합니다.

using 선언에 대한 언어 문법은 다음과 같습니다.

local-using-declaration:
  'using' type using-declarators

using-declarators:
  using-declarator
  using-declarators , using-declarator
  
using-declarator:
  identifier = expression

using 선언에 대한 제한 사항:

  • case 레이블 내부에 직접 나타나지 않을 수 있지만 대신 case 레이블 내의 블록 내에 있어야 합니다.
  • out 변수 선언의 일부로 표시되지 않을 수 있습니다.
  • 각 선언자에 대한 이니셜라이저가 있어야 합니다.
  • 로컬 형식은 IDisposable으로 암시적으로 변환될 수 있거나 using 패턴을 충족해야 합니다.

패턴 기반 사용

언어는 액세스 가능한 ref struct 인스턴스 메서드를 가진 ref struct이라는, Dispose 형식에 대한 삭제 가능한 패턴의 개념을 추가할 것입니다. 삭제 가능한 패턴에 맞는 형식은 using구현하지 않고도 IDisposable 문 또는 선언에 참여할 수 있습니다.

ref struct Resource
{ 
    public void Dispose() { ... }
}

using (var r = new Resource())
{
    // statements
}

이를 통해서 개발자가 using 형식을 위한 ref struct을 활용할 수 있습니다. 이러한 형식은 C# 8에서 인터페이스를 구현할 수 없으므로 using 문에 참여할 수 없습니다.

기존 using 문의 동일한 제한 사항이 여기에 적용됩니다. 지역 변수가 using에서 선언된 경우에는 읽기 전용 상태가 되고, null 값으로 인해 예외가 발생하지 않습니다. 코드 생성은 Dispose를 호출하기 전에는 IDisposable 캐스트가 없다는 점에서만 차이가 납니다.

{
	  Resource r = new Resource();
	  try {
		    // statements
	  }
	  finally {
		    if (r != null) r.Dispose();
	  }
}

삭제 가능한 패턴에 맞게 Dispose 메서드는 액세스 가능한 인스턴스 멤버여야 하며 매개 변수가 없으며 void 반환 형식이 있어야 합니다. 확장 메서드일 수 없습니다.

고려 사항

이러한 고려 사항 중 어느 것도 C# 8에서 구현되지 않았습니다.

블록이 없는 케이스 레이블

using declaration는 실제 수명과 관련된 문제로 인해 case 레이블 안에 직접 존재하는 것이 불법입니다. 한 가지 잠재적인 해결 방법은 동일한 위치에서 out var과 동일한 수명을 제공하는 것입니다. 기능 구현에 대한 추가 복잡성과 해결 편의성(case 레이블에 블록 추가)이 이 경로를 사용하는 것을 정당화하지 않은 것으로 간주되었습니다.

향후 확장

고정 지역

fixed 문에는 using 지역 변수를 가질 수 있는 동기를 부여한 using 문의 모든 속성이 있습니다. 이 기능을 fixed 지역에 확장하는 것을 고려해야 합니다. 수명 및 순서 지정 규칙은 여기에서 usingfixed에 동등하게 적용되어야 합니다.