다음을 통해 공유


파일-로컬 형식

메모

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

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

사양문서에서 기능 사양을 C# 언어 표준에 포함하는 과정에 대해 자세히 알아볼 수 있습니다.

요약

최상위 타입 선언에서 file 수정자를 허용합니다. 형식은 선언된 파일에만 존재합니다.

// File1.cs
namespace NS;

file class Widget
{
}

// File2.cs
namespace NS;

file class Widget // different symbol than the Widget in File1
{
}

// File3.cs
using NS;

var widget = new Widget(); // error: The type or namespace name 'Widget' could not be found.

동기

우리의 주된 동기는 원본 생성기에서 비롯됩니다. 원본 생성기는 사용자의 컴파일에 파일을 추가하여 작동합니다.

  1. 이러한 파일은 컴파일의 나머지 부분으로부터 숨겨져 있지만 선언된 파일 전체에서 사용할 수 있는 구현 세부 정보를 포함할 수 있어야 합니다.
  2. 생성기가 사용자 코드의 선언이나 다른 생성기의 코드와 충돌하지 않는 형식 이름을 "검색"할 필요성을 줄이려고 합니다.

상세 디자인

형식에 file 한정자가 있으면 파일 로컬 형식이라고 합니다.

접근성

file 한정자는 접근성 한정자로 분류되지 않습니다. 타입에 대해 file와 함께 사용할 수 있는 접근 제한자는 없습니다. file 접근성과는 독립적인 개념으로 취급됩니다. 파일-로컬 형식은 중첩될 수 없으므로, file 형식의 경우 기본 접근성 internal만 사용할 수 있습니다.

public file class C1 { } // error
internal file class C2 { } // error
file class C3 { } // ok

명명

구현은 이름이 같은 다른 파일의 파일-로컬 형식이 런타임과 구별되도록 보장합니다. 메타데이터에서 형식의 접근성 및 이름은 구현에서 정의됩니다. 컴파일러가 기능에 적합한 런타임의 향후 액세스 제한 기능을 채택할 수 있도록 하기 위한 것입니다. 초기 구현에서는 internal 접근성이 사용되고 형식이 선언된 파일에 따라 말할 수 없는 생성된 이름이 사용됩니다.

조회

멤버 조회 섹션을 다음과 같이 수정합니다(새 텍스트를굵게 표시합니다).

  • 다음으로, K 0이면 선언에 형식 매개 변수가 포함된 모든 중첩 형식이 제거됩니다. K 0이 아니면 형식 매개 변수 수가 다른 모든 멤버가 제거됩니다. K 0이면 형식 유추 프로세스(§11.6.3)가 형식 인수를 유추할 수 있으므로 형식 매개 변수가 있는 메서드는 제거되지 않습니다.
  • 다음으로 F이 멤버 조회가 발생하는 식을 포함하는 컴파일 단위가 됩니다. 파일 로컬 형식이고 F 선언되지 않은 모든 멤버는 집합에서 제거됩니다.
  • 다음으로, 액세스 가능한 멤버 집합에 파일-로컬 형식이 포함된 경우 파일-로컬 형식이 아닌 모든 멤버가 집합에서 제거됩니다.

비고

이러한 규칙은 선언된 파일 외부의 파일-로컬 형식 사용을 허용하지 않습니다.

또한 이러한 규칙은 파일-로컬 형식이 네임스페이스 또는 비 파일 로컬 형식을 섀도를 허용합니다.

// File1.cs
class C
{
    public static void M() { }
}
// File2.cs
file class C
{
    public static void M() { }
}

class Program
{
    static void Main()
    {
        C.M(); // refers to the 'C' in File2.cs
    }
}

참고로, 사양의 범위 섹션은 업데이트하지 않습니다. 이는 사양에서 설명한 대로 다음과 같기 때문입니다.

이름의 범위 은 이름으로 선언된 엔터티를 이름을 한정하지 않고 참조할 수 있는 프로그램 텍스트의 영역입니다.

실제로 범위는 정규화되지 않은 이름의 조회에만 영향을 줍니다. 우리는 정규화된 이름의 조회에도 영향을 미쳐야 하기 때문에, 이 개념을 활용하는 것은 적합하지 않습니다.

// File1.cs
namespace NS1
{
    file class C
    {
        public static void M() { }
    }
}

namespace NS2
{
    class Program
    {
        public static void M()
        {
            C.M(); // error: C is not in scope
            NS1.C.M(); // ok: C can be accessed through NS1.
        }
    }
}
// File2.cs
namespace NS1
{
    class Program
    {
        C.M(); // error
        NS1.C.M(); // error
    }
}

따라서 형식이 포함된 범위를 기준으로 기능을 지정하지 않고 멤버 조회에서 추가적인 "필터링 규칙"으로 지정합니다.

특성

파일-로컬 클래스는 특성 형식으로 허용되며, 특성 형식이 파일 로컬이 아닌 형식인 것처럼 파일 로컬 형식과 비 파일 로컬 형식 모두에서 특성으로 사용할 수 있습니다. 파일-로컬 특성 형식의 메타데이터 이름은 다른 파일-로컬 형식과 동일한 이름 생성 전략을 계속 진행합니다. 즉, 시간이 지남에 따라 변경될 수 있는 컴파일러의 내부 이름 생성 전략에 따라 필요하므로 하드 코딩된 문자열 이름으로 파일 로컬 형식이 있는지 검색하는 것은 실용적이지 않을 수 있습니다. 그러나 typeof(MyFileLocalAttribute)을 통해 탐지하면 작동합니다.

using System;
using System.Linq;

file class MyFileLocalAttribute : Attribute { }

[MyFileLocalAttribute]
public class C
{
    public static void Main()
    {
        var attribute = typeof(C).CustomAttributes.Where(attr => attr.AttributeType == typeof(MyFileLocalAttribute)).First();
        Console.Write(attribute); // outputs the generated name of the file-local attribute type
    }
}

서명의 사용량

멤버 매개 변수, 반환 및 형식 매개 변수 제약 조건에 파일-로컬 형식이 나타나지 않도록 하는 것이 일반적입니다. 여기서 파일-로컬 형식은 멤버 사용 시점에 범위에 없을 수 있습니다.

파일-로컬이 아닌 타입은, 접근성이 낮은 인터페이스를 구현할 수 있는 형식처럼, 파일-로컬 인터페이스를 구현할 수 있습니다. 인터페이스 멤버에 있는 형식에 따라 다음 섹션의 규칙을 위반할 수 있습니다.

파일-로컬 형식의 멤버에서만 서명 사용 허용

파일 로컬 형식이 서명에만 표시되거나 다른 파일-로컬 형식의 기본 형식으로만 표시되도록 하는 것이 가장 간단한 방법일 수 있습니다.

file class FileBase
{
}

public class Derived : FileBase // error
{
    private FileBase M2() => new FileBase() // error
}

file class FileDerived : FileBase // ok
{
    private FileBase M2() => new FileBase(); // ok
}

이러한 사용은 안전하더라도 명시적 구현에서의 사용은 제한됩니다. 기능의 초기 반복에 대한 규칙을 간소화하기 위해 이 작업을 수행합니다.

file interface I
{
    void M(I i);
}

class C : I
{
    void I.M(I i) { } // error
}

global using static

global using static 지시문에서 파일-로컬 형식을 사용하는 것은 컴파일 시간 오류입니다. 즉,

global using static C; // error

file class C
{
    public static void M() { }
}

구현/오버라이드

파일-로컬 형식 선언은 일반 형식 선언과 마찬가지로 인터페이스를 구현하고 가상 메서드를 재정의할 수 있습니다.

file struct Widget : IEquatable<Widget>
{
    public bool Equals(Widget other) => true;
}