다음을 통해 공유


구조체 16개

16.1 일반

구조체는 데이터 멤버 및 함수 멤버를 포함할 수 있는 데이터 구조를 나타낸다는 측면에서 클래스와 비슷합니다. 그러나 클래스와 달리 구조체는 값 형식이며 힙 할당이 필요하지 않습니다. 형식의 struct 변수에는 해당 데이터가 struct직접 포함되는 반면 클래스 형식의 변수에는 개체라고 하는 데이터에 대한 참조가 포함됩니다.

참고: 구조체는 값 의미 체계가 있는 작은 데이터 구조체에 특히 유용합니다. 복소수, 좌표계의 점 또는 사전의 키-값 쌍이 모두 구조체의 좋은 예입니다. 이러한 데이터 구조의 핵심은 데이터 멤버가 거의 없고 상속 또는 참조 의미 체계를 사용할 필요가 없다는 것입니다. 대신 할당이 참조 대신 값을 복사하는 값 의미 체계를 사용하여 편리하게 구현할 수 있습니다. 끝 메모

§8.3.5에 설명된 대로 C#에서 제공하는 단순 형식(예: int, doublebool)은 실제로 모든 구조체 형식입니다.

16.2 구조체 선언

16.2.1 일반

struct_declaration 새 구조체를 선언하는 type_declaration(§14.7)입니다.

struct_declaration
    : attributes? struct_modifier* 'ref'? 'partial'? 'struct'
      identifier type_parameter_list? struct_interfaces?
      type_parameter_constraints_clause* struct_body ';'?
    ;

struct_declaration 선택적 특성 집합(§22)과 선택적 struct_modifier집합(§16.2.2), 선택적 ref 한정자(§16.2.3), 선택적 부분 한정자(§15.2.7), 키워드 struct구조체 이름을 지정하는 식별자로 구성됩니다. 다음에 선택적 type_parameter_list 사양(§15.2.3) ) 뒤에 선택적 struct_interfaces 사양(§16.2.5) 뒤에 선택적 type_parameter_constraints 절 사양(§15.2.5), struct_body(§16.2.6) 뒤에 세미콜론이 옵니다.

구조체 선언은 type_parameter_list 제공하지 않는 한 type_parameter_constraints_clauses 제공하지 않습니다.

type_parameter_list 제공하는 구조체 선언은 제네릭 구조체 선언입니다. 또한 제네릭 클래스 선언 또는 제네릭 구조체 선언 내에 중첩된 모든 구조체는 제네릭 구조체 선언입니다. 이는 포함된 형식에 대한 형식 인수를 제공하여 생성된 형식(§8.4)을 생성하기 때문에 제네릭 구조체 선언입니다.

키워드를 포함하는 구조체 선언에는 ref struct_interfaces 부분이 없습니다.

16.2.2 구조체 한정자

struct_declaration 필요에 따라 struct_modifier시퀀스를 포함할 수 있습니다.

struct_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'readonly'
    | unsafe_modifier   // unsafe code support
    ;

unsafe_modifier(§23.2)는 안전하지 않은 코드(§23)에서만 사용할 수 있습니다.

동일한 한정자가 구조체 선언에 여러 번 표시되는 것은 컴파일 시간 오류입니다.

readonly, 구조체 선언의 한정자는 클래스 선언(§15.2.2)의 한정자와 동일한 의미를 갖습니다.

readonly 정자는 struct_declaration 인스턴스를 변경할 수 없는 형식을 선언한다는 것을 나타냅니다.

읽기 전용 구조체에는 다음과 같은 제약 조건이 있습니다.

  • 각 인스턴스 필드도 선언 readonly되어야 합니다.
  • 인스턴스 속성 에는 set_accessor_declaration 없습니다(§15.7.3).
  • 필드와 유사한 이벤트(§15.8.2)는 선언하지 않습니다.

읽기 전용 구조체의 인스턴스가 메서드에 전달되면 해당 this 인스턴스는 입력 인수/매개 변수처럼 처리되므로 생성자를 제외한 모든 인스턴스 필드에 대한 쓰기 액세스가 허용되지 않습니다.

16.2.3 참조 한정자

ref 한정자는 struct_declaration 인스턴스가 실행 스택에 할당된 형식을 선언한다는 것을 나타냅니다. 이러한 형식을 ref 구조체 형식이라고합니다. ref 한정자는 인스턴스에 참조와 유사한 필드가 포함될 수 있으며 안전 컨텍스트(§16.4.12)에서 복사되지 않음을 선언합니다. ref 구조체의 안전한 컨텍스트를 결정하는 규칙은 §16.4.12설명되어 있습니다.

다음 컨텍스트에서 ref 구조체 형식을 사용하는 경우 컴파일 시간 오류입니다.

  • 배열의 요소 형식입니다.
  • 한정자가 없는 ref 클래스 또는 구조체 필드의 선언된 형식입니다.
  • boxed to System.ValueType or System.Object.
  • 형식 인수입니다.
  • 튜플 요소의 형식입니다.
  • 비동기 메서드입니다.
  • 반복기입니다.
  • 형식에서 ref struct 형식 또는 형식으로 변환 object 되지 System.ValueType않습니다.
  • 인터페이스를 ref struct 구현하기 위해 형식을 선언해서는 안 됩니다.
  • 형식에서 object System.ValueType 선언되었지만 재정 ref struct 의되지 않은 인스턴스 메서드는 해당 ref struct 형식의 수신기로 호출되지 않습니다.
  • 형식의 ref struct 인스턴스 메서드는 대리자 형식으로의 메서드 그룹 변환에 의해 캡처되지 않습니다.
  • ref 구조체는 람다 식 또는 로컬 함수에 의해 캡처되지 않습니다.

참고: A ref struct 는 해당 컨텍스트에서 암시적 this 매개 변수를 yield return 사용할 수 없으므로 인스턴스 메서드를 선언 async 하거나 인스턴스 메서드 내에서 또는 yield break 문을 사용하지 않습니다. 끝 메모

이러한 제약 조건은 형식의 ref struct 변수가 더 이상 유효하지 않은 스택 메모리 또는 더 이상 유효하지 않은 변수를 참조하지 않도록 합니다.

16.2.4 부분 한정자

partial 정자는 이 struct_declaration 부분 형식 선언임을 나타냅니다. 바깥쪽 네임스페이스 또는 형식 선언 내에서 이름이 같은 여러 부분 구조체 선언은 §15.2.7지정된 규칙에 따라 하나의 구조체 선언을 형성하기 위해 결합됩니다.

16.2.5 구조체 인터페이스

구조체 선언에는 struct_interfaces 사양이 포함될 수 있으며, 이 경우 구조체는 지정된 인터페이스 형식을 직접 구현하는 것으로 합니다. 제네릭 형식 선언(§15.3.9.7) 내에 선언된 중첩 형식을 포함하여 생성된 구조체 형식의 경우 지정된 인터페이스의 각 type_parameter 대해 생성된 형식의 해당 type_argument 대체하여 구현된 각 인터페이스 형식을 가져옵니다.

struct_interfaces
    : ':' interface_type_list
    ;

부분 구조체 선언(§15.2.7)의 여러 부분에 대한 인터페이스 처리는 §15.2.4.3에서 자세히 설명합니다.

인터페이스 구현은 §18.6에서 자세히 설명합니다.

16.2.6 구조체 본문

구조체의 struct_body 구조체의 멤버를 정의합니다.

struct_body
    : '{' struct_member_declaration* '}'
    ;

16.3 구조체 멤버

구조체의 멤버는 해당 struct_member_declaration도입된 멤버와 형식System.ValueType에서 상속된 멤버로 구성됩니다.

struct_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | static_constructor_declaration
    | type_declaration
    | fixed_size_buffer_declaration   // unsafe code support
    ;

fixed_size_buffer_declaration(§23.8.2)는 안전하지 않은 코드(§23)에서만 사용할 수 있습니다.

참고: finalizer_declaration 제외한 모든 종류의 class_member_declarationstruct_member_declaration. 끝 메모

§16.4명시된 차이점을 제외하고 § 15.3에서 §15.12까지의 클래스 멤버에 대한 설명은 구조체 멤버에게도 적용됩니다.

16.4 클래스 및 구조체 차이점

16.4.1 일반

구조체는 다음과 같은 몇 가지 중요한 방법으로 클래스와 다릅니다.

  • 구조체는 값 형식(§16.4.2)입니다.
  • 모든 구조체 형식은 클래스 System.ValueType 에서 암시적으로 상속됩니다(§16.4.3).
  • 구조체 형식의 변수에 할당하면 할당되는 값의 복사본이 만들어집니다(§16.4.4).
  • 구조체의 기본값은 모든 필드를 기본값(§16.4.5)으로 설정하여 생성되는 값입니다.
  • Boxing 및 unboxing 작업은 구조체 형식과 특정 참조 형식(§16.4.6) 간에 변환하는 데 사용됩니다.
  • 구조체 멤버 내에서 의미 this 는 다릅니다(§16.4.7).
  • 구조체에 대한 인스턴스 필드 선언은 변수 이니셜라이저(§16.4.8)를 포함할 수 없습니다.
  • 구조체는 매개 변수가 없는 인스턴스 생성자(§16.4.9)를 선언할 수 없습니다.
  • 구조체는 종료자를 선언할 수 없습니다.

16.4.2 값 의미 체계

구조체는 값 형식(§8.3)이며 값 의미 체계가 있다고 합니다. 반면 클래스는 참조 형식(§8.2)이며 참조 의미 체계가 있다고 합니다.

구조체 형식의 변수는 구조체의 데이터를 직접 포함하는 반면 클래스 형식의 변수에는 데이터가 포함된 개체에 대한 참조가 포함됩니다. 구조체 B 에 형식 A 의 인스턴스 필드가 포함되어 있고 A 구조체 형식인 경우, 이 구조체는 형식에 따라 달라지거나 생성된 B형식에 대한 A B 컴파일 시간 오류입니다. A struct X형식Y의 인스턴스 필드가 포함된 경우 X 구조체 Y 따라 직접 달라집니다. 이 정의를 감안할 때 구조체가 의존하는 전체 구조체 집합은 관계에 따라 직접의 전이적 폐쇄입니다.

예제:

struct Node
{
    int data;
    Node next; // error, Node directly depends on itself
}

는 고유한 형식의 인스턴스 필드를 포함하기 때문에 Node 오류가 발생합니다. 또 다른 예제

struct A { B b; }
struct B { C c; }
struct C { A a; }

는 각 형식 ABC 이 서로 달라지므로 오류가 발생합니다.

끝 예제

클래스를 사용하면 두 변수가 동일한 개체를 참조할 수 있으므로 한 변수에 대한 작업이 다른 변수에서 참조하는 개체에 영향을 줄 수 있습니다. 구조체를 사용하면 변수 각각에 고유한 데이터 복사본이 있으며(참조 매개 변수의 경우 제외) 한 매개 변수에 대한 작업이 다른 매개 변수에 영향을 줄 수 없습니다. 또한 명시적으로 nullable(§8.3.12)을 제외하고 구조체 형식의 값은 사용할 수 null없습니다.

참고: 구조체에 참조 형식의 필드가 포함된 경우 참조되는 개체의 내용을 다른 작업에 의해 변경할 수 있습니다. 그러나 필드 자체의 값( 즉, 참조하는 개체)은 다른 구조체 값의 변형을 통해 변경할 수 없습니다. 끝 메모

: 다음을 지정합니다.

struct Point
{
    public int x, y;

    public Point(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    static void Main()
    {
        Point a = new Point(10, 10);
        Point b = a;
        a.x = 100;
        Console.WriteLine(b.x);
    }
}

출력은 .입니다 10. 할당은 값 bb a 복사본을 만들므로 할당의 영향을 a.x받지 않습니다. 대신 클래스로 선언되었으면 Point 출력 100 은 동일한 개체를 참조하기 때문 a 입니다 b .

끝 예제

16.4.3 상속

모든 구조체 형식은 클래스 System.ValueType에서 암시적으로 상속되며, 클래스에서 object상속됩니다. 구조체 선언은 구현된 인터페이스 목록을 지정할 수 있지만 구조체 선언에서 기본 클래스를 지정할 수는 없습니다.

구조체 형식은 추상화되지 않으며 항상 암시적으로 봉인됩니다. abstract 따라서 구조체 선언에는 한 sealed 정자가 허용되지 않습니다.

구조체에 대해 상속이 지원되지 않으므로 구조체 멤버protectedprivate protected의 선언된 접근성은 또는 protected internal.입니다.

구조체의 함수 멤버는 추상 또는 가상일 수 없으며 한 override 정자는 상속된 System.ValueType메서드만 재정의할 수 있습니다.

16.4.4 할당

구조체 형식의 변수에 할당하면 할당되는 값의 복사본이 만들어집니다. 이는 참조를 복사하지만 참조로 식별된 개체는 복사하지 않는 클래스 형식의 변수에 대한 할당과 다릅니다.

할당과 마찬가지로 구조체가 값 매개 변수로 전달되거나 함수 멤버의 결과로 반환될 때 구조체의 복사본이 만들어집니다. 참조 매개 변수를 사용하여 함수 멤버에 대한 참조로 구조체를 전달할 수 있습니다.

구조체의 속성 또는 인덱서가 할당 대상인 경우 속성 또는 인덱서 액세스와 연결된 인스턴스 식은 변수로 분류되어야 합니다. 인스턴스 식이 값으로 분류되면 컴파일 시간 오류가 발생합니다. 이 내용은 §12.21.2자세히 설명되어 있습니다.

16.4.5 기본값

§9.3설명된 대로 여러 종류의 변수가 만들어지면 자동으로 기본값으로 초기화됩니다. 클래스 형식 및 기타 참조 형식의 변수의 경우 이 기본값은 .입니다 null. 그러나 구조체는 사용할 수 없는 null값 형식이므로 구조체의 기본값은 모든 값 형식 필드를 기본값으로 설정하고 모든 참조 형식 필드를 null로 설정하여 생성되는 값입니다.

: 위에 선언된 구조체를 참조 Point 하는 예제

Point[] a = new Point[100];

는 배열의 각 Point 값을 0으로 설정 x y 하여 생성되는 값으로 초기화합니다.

끝 예제

구조체의 기본값은 구조체의 기본 생성자가 반환하는 값(§8.3.3)에 해당합니다. 클래스와 달리 구조체는 매개 변수가 없는 인스턴스 생성자를 선언할 수 없습니다. 대신 모든 구조체에는 모든 필드를 기본값으로 설정하여 발생하는 값을 항상 반환하는 매개 변수가 없는 인스턴스 생성자가 암시적으로 있습니다.

참고: 구조체는 기본 초기화 상태를 유효한 상태로 간주하도록 설계해야 합니다. 예제에서

struct KeyValuePair
{
    string key;
    string value;

    public KeyValuePair(string key, string value)
    {
        if (key == null || value == null)
        {
            throw new ArgumentException();
        }

        this.key = key;
        this.value = value;
    }
}

사용자 정의 인스턴스 생성자는 명시적으로 호출되는 경우에만 값으로부터 null 보호합니다. 변수에 KeyValuePair 기본값 초기화 key 가 적용되는 경우 필드와 value 필드가 null있으며 이 상태를 처리하도록 구조체를 준비해야 합니다.

끝 메모

16.4.6 Boxing 및 unboxing

클래스 형식의 값은 컴파일 타임에 참조를 object 다른 형식으로 처리하여 클래스에서 구현하는 형식 또는 인터페이스 형식으로 변환할 수 있습니다. 마찬가지로 형식 object 값 또는 인터페이스 형식의 값은 참조를 변경하지 않고 클래스 형식으로 다시 변환할 수 있습니다(물론 이 경우 런타임 형식 검사가 필요).

구조체는 참조 형식이 아니므로 이러한 작업은 구조체 형식에 대해 다르게 구현됩니다. 구조체 형식의 값이 특정 참조 형식(§10.2.9정의된 대로)으로 변환되면 boxing 작업이 수행됩니다. 마찬가지로 특정 참조 형식의 값(§10.3.7정의됨)이 구조체 형식으로 다시 변환되면 unboxing 작업이 수행됩니다. 클래스 형식에 대한 동일한 작업과 주요 차이점은 boxing 및 unboxing 은 구조체 값을 boxed 인스턴스로 또는 바깥으로 복사 한다는 것입니다.

참고: Boxing 또는 unboxing 작업 후에는 unboxed struct 에 대한 변경 내용이 boxed struct에 반영되지 않습니다. 끝 메모

boxing 및 unboxing에 대한 자세한 내용은 §10.2.9§10.3.7을 참조하세요.

16.4.7 이 것의 의미

구조체의 this 의미는 §12.8.14설명된 대로 클래스의 this 의미와 다릅니다. 구조체 형식이 상속된 System.ValueType 가상 메서드(예: Equals, GetHashCode또는 ToString)를 재정의하는 경우 구조체 형식의 인스턴스를 통해 가상 메서드를 호출해도 boxing이 발생하지 않습니다. 구조체가 형식 매개 변수로 사용되고 호출이 형식 매개 변수 형식의 인스턴스를 통해 발생하는 경우에도 마찬가지입니다.

예제:

struct Counter
{
    int value;
    public override string ToString() 
    {
        value++;
        return value.ToString();
    }
}

class Program
{
    static void Test<T>() where T : new()
    {
        T x = new T();
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
        Console.WriteLine(x.ToString());
    }

    static void Main() => Test<Counter>();
}

프로그램의 출력은 다음과 같습니다.

1
2
3

부작용이 있는 것은 잘못된 스타일 ToString 이지만 이 예제에서는 세 가지 호출에 대해 boxing이 발생하지 않음을 보여 줍니다 x.ToString().

끝 예제

마찬가지로 멤버가 값 형식 내에서 구현될 때 제약이 있는 형식 매개 변수의 멤버에 액세스할 때는 boxing이 암시적으로 발생하지 않습니다. 예를 들어 인터페이스 ICounter 에 값을 수정하는 데 사용할 수 있는 메서드 Increment가 포함되어 있다고 가정합니다. 제약 조건으로 사용되는 경우 ICounter 메서드의 Increment 구현은 호출된 변수 Increment 에 대한 참조를 사용하여 호출되며, 상자가 있는 복사본은 호출되지 않습니다.

예제:

interface ICounter
{
    void Increment();
}

struct Counter : ICounter
{
    int value;

    public override string ToString() => value.ToString();

    void ICounter.Increment() => value++;
}

class Program
{
    static void Test<T>() where T : ICounter, new()
    {
        T x = new T();
        Console.WriteLine(x);
        x.Increment();              // Modify x
        Console.WriteLine(x);
        ((ICounter)x).Increment();  // Modify boxed copy of x
        Console.WriteLine(x);
    }

    static void Main() => Test<Counter>();
}

변수x의 값을 수정하는 Increment 첫 번째 호출입니다. 이는 boxed x복사본의 값을 수정하는 두 번째 호출Increment과 동일하지 않습니다. 따라서 프로그램의 출력은 다음과 같습니다.

0
1
1

끝 예제

16.4.8 필드 이니셜라이저

§16.4.5설명된 대로 구조체의 기본값은 모든 값 형식 필드를 기본값으로 설정하고 모든 참조 형식 필드를 로 설정하는 결과로 생성되는 값으로 null구성됩니다. 이러한 이유로 구조체는 인스턴스 필드 선언에 변수 이니셜라이저를 포함하도록 허용하지 않습니다. 이 제한은 인스턴스 필드에만 적용됩니다. 구조체의 정적 필드는 변수 이니셜라이저를 포함할 수 있습니다.

: 다음

struct Point
{
    public int x = 1; // Error, initializer not permitted
    public int y = 1; // Error, initializer not permitted
}

인스턴스 필드 선언에 변수 이니셜라이저가 포함되므로 오류가 발생했습니다.

끝 예제

16.4.9 생성자

클래스와 달리 구조체는 매개 변수가 없는 인스턴스 생성자를 선언할 수 없습니다. 대신 모든 구조체에는 모든 값 형식 필드를 기본값으로 설정하고 모든 참조 형식 필드를 (§8.3.3)로 설정하여 발생하는 값을 항상 반환하는 null 매개 변수가 없는 인스턴스 생성자가 암시적으로 있습니다. 구조체는 매개 변수가 있는 인스턴스 생성자를 선언할 수 있습니다.

: 다음을 지정합니다.

struct Point
{
    int x, y;

    public Point(int x, int y) 
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    static void Main()
    {
        Point p1 = new Point();
        Point p2 = new Point(0, 0);
    }
}

문은 모두 with x yPoint 만들고 0으로 초기화합니다.

끝 예제

구조체 인스턴스 생성자는 argument_list 양식base()의 생성자 이니셜라이저를 포함할 수 없습니다. 여기서 argument_list 선택 사항입니다.

구조체 인스턴스 생성자의 매개 변수는 this 구조체 형식의 출력 매개 변수에 해당합니다. 따라서 this 생성자가 반환하는 모든 위치에 (§9.4)를 확실히 할당해야 합니다. 마찬가지로, 확실히 할당되기 전에 생성자 본문에서 읽어올 수 없습니다(암시적으로도).

구조체 인스턴스 생성자가 생성자 이니셜라이저를 지정하는 경우 해당 이니셜라이저는 생성자 본문 이전에 발생하는 이에 대한 명확한 할당으로 간주됩니다. 따라서 본문 자체에는 초기화 요구 사항이 없습니다.

: 아래 인스턴스 생성자 구현을 고려합니다.

struct Point
{
    int x, y;

    public int X
    {
        set { x = value; }
    }

    public int Y 
    {
        set { y = value; }
    }

    public Point(int x, int y) 
    {
        X = x; // error, this is not yet definitely assigned
        Y = y; // error, this is not yet definitely assigned
    }
}

생성되는 구조체의 모든 필드가 확실히 할당될 때까지 인스턴스 함수 멤버(속성 XY대한 set 접근자 포함)를 호출할 수 없습니다. 그러나 구조체 대신 클래스인 경우 Point 인스턴스 생성자 구현이 허용됩니다. 여기에는 한 가지 예외가 있으며 자동으로 구현된 속성(§15.7.4)이 포함됩니다. 특정 할당 규칙(§12.21.2)은 특히 해당 구조체 형식의 인스턴스 생성자 내에서 구조체 형식의 자동 속성에 대한 할당을 제외합니다. 이러한 할당은 자동 속성의 숨겨진 지원 필드에 대한 명확한 할당으로 간주됩니다. 따라서 다음이 허용됩니다.

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    {
        X = x; // allowed, definitely assigns backing field
        Y = y; // allowed, definitely assigns backing field
   }
}

end example]

16.4.10 정적 생성자

구조체에 대한 정적 생성자는 클래스와 동일한 규칙 대부분을 따릅니다. 구조체 형식에 대한 정적 생성자의 실행은 다음 이벤트 중 첫 번째 이벤트가 애플리케이션 도메인 내에서 발생하도록 트리거됩니다.

  • 구조체 형식의 정적 멤버가 참조됩니다.
  • 구조체 형식의 명시적으로 선언된 생성자가 호출됩니다.

참고: 구조체 형식의 기본값(§16.4.5)을 만들면 정적 생성자가 트리거되지 않습니다. 예를 들어 배열에 있는 요소의 초기 값이 있습니다. 끝 메모

16.4.11 자동으로 구현된 속성

자동으로 구현된 속성(§15.7.4)은 속성 접근자만 액세스할 수 있는 숨겨진 지원 필드를 사용합니다.

참고: 이 액세스 제한은 자동으로 구현된 속성을 포함하는 구조체의 생성자가 함수 멤버가 호출되거나 생성자가 반환되기 전에 모든 필드가 확실히 할당되는 요구 사항을 충족하기 위해 명시적으로 구현된 속성이 필요하지 않은 명시적 생성자 이니셜라이저가 필요한 경우가 많다는 것을 의미합니다. 끝 메모

16.4.12 안전한 컨텍스트 제약 조건

16.4.12.1 일반

컴파일 타임에 각 식은 해당 인스턴스와 해당 필드의 안전 컨텍스트에 안전하게 액세스할 수 있는 컨텍스트와 연결됩니다. safe-context는 값을 이스케이프하는 것이 안전한 식을 둘러싸는 컨텍스트입니다.

컴파일 시간 형식이 ref 구조체가 아닌 식에는 호출자 컨텍스트의 안전 컨텍스트가 있습니다.

식은 default 모든 형식에 대해 호출자 컨텍스트의 안전 컨텍스트를 가합니다.

컴파일 시간 형식이 ref 구조체인 기본이 아닌 식의 경우 다음 섹션에서 정의한 안전 컨텍스트가 있습니다.

값이 복사될 수 있는 컨텍스트를 기록하는 안전 컨텍스트입니다. safe-context가 있는 식 E1 에서 safe-contextS1S2가 있는 식 E2 으로 할당된 경우 보다 S1넓은 컨텍스트인 경우 S2 오류가 발생합니다.

참조 변수(§9.7.2) 선언 블록, 함수 멤버 및 호출자 컨텍스트에 대해 정의된 ref-safe-context 값과 동일한 세 가지 안전 컨텍스트 값이 있습니다. 식의 안전 컨텍스트는 다음과 같이 사용을 제한합니다.

  • 반환 문의 return e1경우 안전 컨텍스트는 e1 호출자 컨텍스트여야 합니다.
  • 배정 e1 = e2 의 경우 안전 컨텍스트는 e2 적어도 안전 컨텍스트만큼 넓은 컨텍스트 e1여야 합니다.

형식의 인수(형식이 ref 아닌 경우 readonly수신기 포함)가 있는 경우 메서드 호출의 ref struct 경우 안전 컨텍스트S1를 사용하는 경우 인수(수신자 포함)가 보다 S1좁은 안전 컨텍스트를 가질 수 out 없습니다.

16.4.12.2 매개 변수 안전 컨텍스트

인스턴스 메서드의 매개 변수를 포함하여 this ref 구조체 형식의 매개 변수에는 호출자 컨텍스트의 안전 컨텍스트가 있습니다.

16.4.12.3 로컬 변수 안전 컨텍스트

ref 구조체 형식의 지역 변수에는 다음과 같이 안전 컨텍스트가 있습니다.

  • 변수가 루프의 foreach 반복 변수인 경우 변수의 안전 컨텍스트는 루프 식의 foreach 안전 컨텍스트와 동일합니다.
  • 그렇지 않으면 변수의 선언에 이니셜라이저가 있는 경우 변수의 안전 컨텍스트는 해당 이니셜라이저의 안전 컨텍스트와 동일합니다.
  • 그렇지 않으면 변수가 선언 지점에서 초기화되지 않으며 호출자 컨텍스트의 안전 컨텍스트가 있습니다.

16.4.12.4 필드 안전 컨텍스트

형식이 ref 구조체 형식 F 인 필드에 e.F대한 참조에는 안전 컨텍스트와 동일한 안전 컨텍스트e가 있습니다.

16.4.12.5 연산자

사용자 정의 연산자의 애플리케이션은 메서드 호출(§16.4.12.6)으로 처리됩니다.

결과의 안전 컨텍스트와 같은 e1 + e2 c ? e1 : e2값을 생성하는 연산자의 경우 연산자의 피연산자의 안전 컨텍스트 중에서 가장 좁은 컨텍스트입니다. 결과적으로 값을 생성하는 +e단항 연산자의 경우 결과의 안전 컨텍스트는 피연산자의 안전 컨텍스트입니다.

참고: 조건부 연산자의 첫 번째 피연산자는 안전 bool컨텍스트가 호출자 컨텍스트이므로 결과 안전 컨텍스트는 두 번째 및 세 번째 피연산자의 가장 좁은 안전 컨텍스트입니다. 끝 메모

16.4.12.6 메서드 및 속성 호출

메서드 호출 e1.M(e2, ...) 또는 속성 호출 e.P 로 인한 값은 다음 컨텍스트 중 가장 작은 안전 컨텍스트를 가합니다.

  • caller-context.
  • 모든 인수 식(수신기 포함)의 안전 컨텍스트입니다.

속성 호출(또는 get set)은 위의 규칙에 따라 기본 메서드의 메서드 호출로 처리됩니다.

16.4.12.7 stackalloc

stackalloc 식의 결과에 함수 멤버의 safe-context가 있습니다.

16.4.12.8 생성자 호출

생성자를 호출하는 식은 new 생성되는 형식을 반환하는 것으로 간주되는 메서드 호출과 동일한 규칙을 준수합니다.

또한 안전 컨텍스트는 이니셜라이저가 있는 경우 재귀적으로 모든 개체 이니셜라이저 식의 모든 인수 및 피연산자의 안전 컨텍스트 중 가장 작습니다.

참고: 이러한 규칙은 다음 형식의 생성자가 없는 것을 사용합니다 Span<T> .

public Span<T>(ref T p)

이러한 생성자는 필드와 Span<T> 구별할 수 없는 필드로 사용되는 인스턴스를 ref 만듭니다. 이 문서에 설명된 안전 규칙은 C# 또는 .NET에서 유효한 구문이 아닌 필드에 따라 달라집니다 ref . 끝 메모