Типы структур (справочник по 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.

Структура readonlyreadonly struct

Начиная с C# версии 7.2, чтобы объявить, что тип структуры является неизменяемым, используйте модификатор readonly:Beginning with C# 7.2, you use the readonly modifier to declare that a structure type is immutable:

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 должны быть доступны только для чтения: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.

Члены экземпляров readonlyreadonly 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;
    }
    

    Можно также применить модификатор readonly к методам, переопределяющим методы, объявленные в System.Object.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.

    Примечание

    Компилятор объявляет метод доступа get автоматически реализуемого свойства как readonly независимо от наличия модификатора 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 и более поздних версий вы можете применить модификатор readonly к свойству или индексатору с помощью метода доступа init: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. Однако можно инициализировать статическое поле или поле константы или статическое свойство при его объявлении.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.

Структура refref 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.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.
  • Переменную структуры ref нельзя использовать в методе async.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, объедините модификаторы readonly и ref в объявлении типа (модификатор 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>.

ПреобразованияConversions

Для любого типа структуры (за исключением типов структурыref ) существует упаковка-преобразование и распаковка-преобразование в типы System.ValueType и System.Object и из них.For any structure type (except ref struct types), there exist boxing and unboxing conversions to and from the System.ValueType and System.Object types. Существуют упаковка-преобразование и распаковка-преобразование между типом структуры и любым интерфейсом, который он реализует.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