구조체 형식(C# 참조)Structure types (C# reference)

‘구조체 형식’은 데이터와 관련 기능을 캡슐화할 수 있는 값 형식입니다. A structure type (or struct type) is a value type that can encapsulate data and related functionality. 구조체 형식은 struct 키워드를 사용하여 정의합니다.You use the struct keyword to define a structure type:

public struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public override string ToString() => $"({X}, {Y})";
}

구조체 형식은 ‘값 의미 체계’를 갖습니다. Structure types have value semantics. 즉, 구조체 형식의 변수는 해당 형식의 인스턴스를 포함합니다.That is, a variable of a structure type contains an instance of the type. 기본적으로 변수 값은 할당 시에, 인수를 메서드에 전달할 때, 그리고 메서드 결과를 반환할 때 복사됩니다.By default, variable values are copied on assignment, passing an argument to a method, and returning a method result. 구조체 형식 변수의 경우, 해당 형식의 인스턴스가 복사됩니다.In the case of a structure-type variable, an instance of the type is copied. 자세한 내용은 값 형식을 참조하세요.For more information, see Value types.

구조체 형식은 일반적으로 동작을 거의 제공하지 않거나 전혀 제공하지 않는 작은 데이터 중심 형식을 설계하는 데 사용합니다.Typically, you use structure types to design small data-centric types that provide little or no behavior. 예를 들어, .NET에서는 구조체 형식을 사용하여 숫자(정수실수), 부울 값, 유니코드 문자, 시간 인스턴스를 표현합니다.For example, .NET uses structure types to represent a number (both integer and real), a Boolean value, a Unicode character, a time instance. 형식의 동작이 중요한 경우에는 클래스를 정의하는 것이 좋습니다.If you're focused on the behavior of a type, consider defining a class. 클래스 형식은 ‘참조 의미 체계’를 갖습니다. Class types have reference semantics. 즉, 클래스 형식의 변수는 인스턴스 자체가 아닌 해당 형식의 인스턴스에 대한 참조를 포함합니다.That is, a variable of a class type contains a reference to an instance of the type, not the instance itself.

구조체 형식에는 값 의미 체계가 있기 때문에 변경할 수 없는 구조체 형식을 정의하는 것이 좋습니다.Because structure types have value semantics, we recommend you to define immutable structure types.

readonly 구조체readonly struct

C# 7.2부터 readonly 한정자를 사용하여 구조체 형식을 변경할 수 없도록 선언합니다.Beginning with C# 7.2, you use the readonly modifier to declare that a structure type is immutable. readonly 구조체의 모든 데이터 멤버는 다음과 같이 읽기 전용이어야 합니다.All data members of a readonly struct must be read-only as follows:

  • 모든 필드 선언에는 readonly 한정자가 있어야 합니다.Any field declaration must have the readonly modifier
  • 자동 구현된 속성을 포함하여 모든 속성은 읽기 전용이어야 합니다.Any property, including auto-implemented ones, must be read-only. C# 9.0 이상에서는 속성에 init 접근자가 있을 수 있습니다.In C# 9.0 and later, a property may have an init accessor.

이렇게 하면 readonly 구조체의 멤버가 구조체의 상태를 수정하지 않습니다.That guarantees that no member of a readonly struct modifies the state of the struct. C# 8.0 이상에서는 생성자를 제외한 다른 인스턴스 멤버는 암시적으로 readonly임을 의미합니다.In C# 8.0 and later, that means that other instance members except constructors are implicitly readonly.

참고

readonly 구조체에서 변경 가능한 참조 형식의 데이터 멤버는 여전히 자체 상태를 변경할 수 있습니다.In a readonly struct, a data member of a mutable reference type still can mutate its own state. 예를 들어 List<T> 인스턴스를 바꿀 수는 없지만 새 요소를 추가할 수는 있습니다.For example, you can't replace a List<T> instance, but you can add new elements to it.

다음 코드는 C# 9.0 이상에서 사용할 수 있는 init 전용 속성 setter를 사용하여 readonly 구조체를 정의합니다.The following code defines a readonly struct with init-only property setters, available in C# 9.0 and later:

public readonly struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; init; }
    public double Y { get; init; }

    public override string ToString() => $"({X}, {Y})";
}

readonly 인스턴스 멤버readonly instance members

C# 8.0부터 readonly 한정자를 사용하여 인스턴스 멤버가 구조체의 상태를 수정하지 않도록 선언할 수도 있습니다.Beginning with C# 8.0, you can also use the readonly modifier to declare that an instance member doesn't modify the state of a struct. 전체 구조체 형식을 readonly로 선언할 수 없는 경우 readonly 한정자를 사용하여 구조체의 상태를 수정하지 않는 인스턴스 멤버를 표시합니다.If you can't declare the whole structure type as readonly, use the readonly modifier to mark the instance members that don't modify the state of the struct.

readonly 인스턴스 멤버 내에서 구조체의 인스턴스 필드에 할당할 수 없습니다.Within a readonly instance member, you can't assign to structure's instance fields. 그러나 readonly 멤버는readonly가 아닌 멤버를 호출할 수 있습니다.However, a readonly member can call a non-readonly member. 이 경우 컴파일러는 구조체 인스턴스의 복사본을 만들고 해당 복사본에서 readonly가 아닌 멤버를 호출합니다.In that case the compiler creates a copy of the structure instance and calls the non-readonly member on that copy. 따라서 원래 구조체 인스턴스는 수정되지 않습니다.As a result, the original structure instance is not modified.

일반적으로 다음 종류의 인스턴스 멤버에 readonly 한정자를 적용합니다.Typically, you apply the readonly modifier to the following kinds of instance members:

  • 메서드:methods:

    public readonly double Sum()
    {
        return X + Y;
    }
    

    System.Object에 선언된 메서드를 재정의하는 메서드에 readonly 한정자를 적용할 수도 있습니다.You can also apply the readonly modifier to methods that override methods declared in System.Object:

    public readonly override string ToString() => $"({X}, {Y})";
    
  • 속성 및 인덱서:properties and indexers:

    private int counter;
    public int Counter
    {
        readonly get => counter;
        set => counter = value;
    }
    

    속성 또는 인덱서의 두 접근자에 모두 readonly 한정자를 적용해야 하는 경우 속성 또는 인덱서의 선언에 해당 한정자를 적용합니다.If you need to apply the readonly modifier to both accessors of a property or indexer, apply it in the declaration of the property or indexer.

    참고

    컴파일러는 속성 선언에 readonly 한정자가 있는지 여부와 관계없이 자동 구현 속성get 접근자를 readonly로 선언합니다.The compiler declares a get accessor of an auto-implemented property as readonly, regardless of presence of the readonly modifier in a property declaration.

    C# 9.0 이상에서는 init 접근자를 사용하여 속성 또는 인덱서에 readonly 한정자를 적용할 수 있습니다.In C# 9.0 and later, you may apply the readonly modifier to a property or indexer with an init accessor:

    public readonly double X { get; init; }
    

구조체 형식의 정적 멤버에는 readonly 한정자를 적용할 수 없습니다.You can't apply the readonly modifier to static members of a structure type.

컴파일러는 성능 최적화를 위해 readonly 한정자를 사용할 수 있습니다.The compiler may make use of the readonly modifier for performance optimizations. 자세한 내용은 안전하고 효율적인 C# 코드 작성을 참조하세요.For more information, see Write safe and efficient C# code.

구조체 형식 설계의 제한 사항Limitations with the design of a structure type

구조체 형식을 설계할 때는 클래스 형식과 같은 기능을 사용할 수 있으나, 다음과 같은 예외가 적용됩니다.When you design a structure type, you have the same capabilities as with a class type, with the following exceptions:

  • 매개 변수가 없는 생성자를 선언할 수 없습니다.You can't declare a parameterless constructor. 모든 구조체 형식은 이미 해당 형식의 기본값을 생성하는 매개 변수 없는 암시적 생성자를 제공합니다.Every structure type already provides an implicit parameterless constructor that produces the default value of the type.

  • 인스턴스 필드 또는 속성은 선언과 동시에 초기화할 수 없습니다.You can't initialize an instance field or property at its declaration. 단, static 또는 const 필드 또는 정적 속성은 선언과 동시에 초기화할 수 있습니다.However, you can initialize a static or const field or a static property at its declaration.

  • 구조체 형식의 생성자는 해당 형식의 모든 인스턴스 필드를 초기화해야 합니다.A constructor of a structure type must initialize all instance fields of the type.

  • 구조체 형식은 다른 클래스 또는 구조체 형식에서 상속할 수 없으며, 클래스의 기본이 될 수 없습니다.A structure type can't inherit from other class or structure type and it can't be the base of a class. 단, 구조체 형식은 인터페이스를 구현할 수 있습니다.However, a structure type can implement interfaces.

  • 구조체 형식 내에서 종료자를 선언할 수 없습니다.You can't declare a finalizer within a structure type.

구조체 형식의 인스턴스화Instantiation of a structure type

C#에서는 선언된 변수를 사용하려면 먼저 초기화해야 합니다.In C#, you must initialize a declared variable before it can be used. 구조체 형식 변수는 null일 수 없으므로(null 허용 값 형식의 변수인 경우 제외), 해당 형식의 인스턴스를 인스턴스화해야 합니다.Because a structure-type variable can't be null (unless it's a variable of a nullable value type), you must instantiate an instance of the corresponding type. 이 작업은 몇 가지 방법으로 수행할 수 있습니다.There are several ways to do that.

일반적으로, 구조체 형식은 new 연산자를 사용하여 적절한 생성자를 호출함으로써 인스턴스화합니다.Typically, you instantiate a structure type by calling an appropriate constructor with the new operator. 모든 구조체 형식은 하나 이상의 생성자를 갖습니다.Every structure type has at least one constructor. 이는 해당 형식의 기본값을 생성하는 매개 변수 없는 암시적 생성자입니다.That's an implicit parameterless constructor, which produces the default value of the type. 기본값 식을 사용하여 형식의 기본값을 생성할 수도 있습니다.You can also use a default value expression to produce the default value of a type.

구조체 형식의 모든 인스턴스 필드가 액세스 가능한 경우, new 연산자 없이 인스턴스화할 수도 있습니다.If all instance fields of a structure type are accessible, you can also instantiate it without the new operator. 이 경우 인스턴스를 처음 사용하기 전에 모든 인스턴스 필드를 초기화해야 합니다.In that case you must initialize all instance fields before the first use of the instance. 다음 예제에서는 해당 작업을 수행하는 방법을 보여줍니다.The following example shows how to do that:

public static class StructWithoutNew
{
    public struct Coords
    {
        public double x;
        public double y;
    }

    public static void Main()
    {
        Coords p;
        p.x = 3;
        p.y = 4;
        Console.WriteLine($"({p.x}, {p.y})");  // output: (3, 4)
    }
}

기본 제공 값 형식의 경우, 해당 리터럴을 사용하여 해당 형식의 값을 지정합니다.In the case of the built-in value types, use the corresponding literals to specify a value of the type.

참조를 통해 구조체 형식 변수 전달Passing structure-type variables by reference

구조체 형식 변수를 메서드에 인수로 전달하거나 메서드에서 구조체 형식 값을 반환할 경우, 구조체 형식의 인스턴스 전체가 복사됩니다.When you pass a structure-type variable to a method as an argument or return a structure-type value from a method, the whole instance of a structure type is copied. 이로 인해 구조체 형식이 많이 사용되는 고성능 시나리오에서 코드의 성능이 저하될 수 있습니다.That can affect the performance of your code in high-performance scenarios that involve large structure types. 구조체 형식 변수를 참조를 통해 전달하면 값이 복사되지 않도록 할 수 있습니다.You can avoid value copying by passing a structure-type variable by reference. 참조를 통해 인수를 전달해야 한다는 사실을 나타내려면 ref, out 또는 in 메서드 매개 변수 한정자를 사용합니다.Use the ref, out, or in method parameter modifiers to indicate that an argument must be passed by reference. 참조를 통해 메서드 결과를 반환하려면 ref returns를 사용합니다.Use ref returns to return a method result by reference. 자세한 내용은 안전하고 효율적인 C# 코드 작성을 참조하세요.For more information, see Write safe and efficient C# code.

ref 구조체ref struct

C# 7.2부터 구조체 형식 선언에 ref 한정자를 사용할 수 있습니다.Beginning with C# 7.2, you can use the ref modifier in the declaration of a structure type. ref 구조체 형식의 인스턴스는 스택에 할당되며 관리되는 힙으로 이스케이프할 수 없습니다.Instances of a ref struct type are allocated on the stack and can't escape to the managed heap. 이를 위해 컴파일러는 다음과 같이 ref 구조체 형식의 사용을 제한합니다.To ensure that, the compiler limits the usage of ref struct types as follows:

  • ref 구조체는 배열의 요소 형식일 수 없습니다.A ref struct can't be the element type of an array.
  • ref 구조체는 클래스의 필드 또는 비 ref 구조체의 선언된 형식일 수 없습니다.A ref struct can't be a declared type of a field of a class or a non-ref struct.
  • ref 구조체는 인터페이스를 구현할 수 없습니다.A ref struct can't implement interfaces.
  • ref 구조체는 System.ValueType 또는 System.Object에 boxing할 수 없습니다.A ref struct can't be boxed to System.ValueType or System.Object.
  • ref 구조체는 형식 인수일 수 없습니다.A ref struct can't be a type argument.
  • 람다 식 또는 로컬 함수에서 ref 구조체 변수를 캡처할 수 없습니다.A ref struct variable can't be captured by a lambda expression or a local function.
  • async 메서드에서는 ref 구조체 변수를 사용할 수 없습니다.A ref struct variable can't be used in an async method. 그러나 동기 메서드에서는 ref 구조체 변수(예: Task 또는 Task<TResult>를 반환하는 변수)를 사용할 수 있습니다.However, you can use ref struct variables in synchronous methods, for example, in those that return Task or Task<TResult>.
  • 반복기에서는 ref 구조체 변수를 사용할 수 없습니다.A ref struct variable can't be used in iterators.

일반적으로 ref 구조체 형식의 데이터 멤버도 포함하는 형식이 필요한 경우 ref 구조체 형식을 정의합니다.Typically, you define a ref struct type when you need a type that also includes data members of ref struct types:

public ref struct CustomRef
{
    public bool IsValid;
    public Span<int> Inputs;
    public Span<int> Outputs;
}

ref 구조체를 readonly로 선언하려면 형식 선언에서 readonlyref 한정자를 결합합니다(readonly 한정자는 ref 한정자 앞에 와야함).To declare a ref struct as readonly, combine the readonly and ref modifiers in the type declaration (the readonly modifier must come before the ref modifier):

public readonly ref struct ConversionRequest
{
    public ConversionRequest(double rate, ReadOnlySpan<double> values)
    {
        Rate = rate;
        Values = values;
    }

    public double Rate { get; }
    public ReadOnlySpan<double> Values { get; }
}

.NET에서 ref 구조체의 예는 System.Span<T>System.ReadOnlySpan<T>입니다.In .NET, examples of a ref struct are System.Span<T> and System.ReadOnlySpan<T>.

구조체 제약 조건struct constraint

struct 제약 조건struct 키워드를 사용하여 형식 매개 변수가 null을 허용하지 않는 값 형식이라고 지정할 수도 있습니다.You also use the struct keyword in the struct constraint to specify that a type parameter is a non-nullable value type. 구조체 형식과 열거형 형식 모두 struct 제약 조건을 충족합니다.Both structure and enumeration types satisfy the struct constraint.

변환Conversions

모든 구조체 형식(ref 구조체 형식 제외)에는 System.ValueTypeSystem.Object 형식의 boxing 및 unboxing 변환이 있습니다.For any structure type (except ref struct types), there exist boxing and unboxing conversions to and from the System.ValueType and System.Object types. 구조체 형식과 구조체 형식이 구현하는 인터페이스 간에도 boxing 및 unboxing 변환이 있습니다.There exist also boxing and unboxing conversions between a structure type and any interface that it implements.

C# 언어 사양C# language specification

자세한 내용은 C# 언어 사양구조체 섹션을 참조하세요.For more information, see the Structs section of the C# language specification.

C# 7.2 이상에 도입된 기능에 대한 자세한 내용은 다음 기능 제안 노트를 참조하세요.For more information about features introduced in C# 7.2 and later, see the following feature proposal notes:

참조See also