A structure type (or struct type) is a value type that can encapsulate data and related functionality.
ms.custom: "updateeachrelease"
The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.
The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.
Use the struct keyword to define a structure type:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csStructExample
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}For information about ref struct and readonly ref struct types, see the ref structure types article.
Structure types have value semantics. That is, a variable of a structure type contains an instance of the type. By default, the system copies variable values on assignment, when passing an argument to a method, and when returning a method result. For structure-type variables, the system copies an instance of the type. For more information, see Value types.
Typically, you use structure types to design small data-centric types that provide little or no behavior. For example, .NET uses structure types to represent a number (both integer and real), a Boolean value, a Unicode character, and 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 define immutable structure types.
readonly struct
Use the readonly modifier to declare that a structure type is immutable. All data members of a readonly struct must be read-only as follows:
- Any field declaration must have the
readonlymodifier. - Any property, including automatically implemented ones, must be read-only or
initonly. Init-only setters are only available from C# version 9 onwards.
This rule guarantees that no member of a readonly struct modifies the state of the struct. All other instance members except constructors are implicitly readonly.
The following code defines a readonly struct with init-only property setters:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csReadonlyStruct
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}readonly instance members
Use the readonly modifier to declare that an instance member doesn't modify the state of a struct. 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.
Within a readonly instance member, you can't assign to the structure's instance fields. However, a readonly member can call a non-readonly member. 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 isn't modified.
Typically, you apply the readonly modifier to the following kinds of instance members:
- Methods:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csReadonlyMethod
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
} You can also apply the readonly modifier to methods that override methods declared in System.Object:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csReadonlyOverride
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}- Properties and indexers:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csReadonlyProperty
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
} 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.
You can apply the readonly modifier to a property or indexer with an init accessor:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csReadonlyWithInit
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}You can apply the readonly modifier to static fields of a structure type, but not to any other static members, such as properties or methods.
The compiler can make use of the readonly modifier for performance optimizations. For more information, see Avoiding allocations.
Nondestructive mutation
Use the with expression to create a copy of a structure-type instance with the specified properties and fields changed. Use object initializer syntax to specify which members to modify and their new values, as the following example shows:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csWithExpression
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}record struct
You can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both record struct and readonly record struct types. A record struct can't be a ref struct. For more information and examples, see Records.
Inline arrays
Starting with C# 12, you can declare inline arrays as a struct type:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csDeclareInlineArray
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}An inline array is a structure that contains a contiguous block of N elements of the same type. It's a safe-code equivalent of the fixed buffer declaration available only in unsafe code. An inline array is a struct with the following characteristics:
- It contains a single field.
- The struct doesn't specify an explicit layout.
In addition, the compiler validates the System.Runtime.CompilerServices.InlineArrayAttribute attribute:
- The length must be greater than zero (
> 0). - The target type must be a struct.
In most cases, you can access an inline array like an array, both to read and write values. You can also use the range and index operators.
There are minimal restrictions on the type of the single field of an inline array. It can't be a pointer type:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csDeclareInlineArrayWithPointer
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}But it can be any reference type, or any value type:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csDeclareInlineArrayWithReferenceType
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}You can use inline arrays with almost any C# data structure.
Inline arrays are an advanced language feature. They're intended for high-performance scenarios where an inline, contiguous block of elements is faster than other alternative data structures. You can learn more about inline arrays from §16.6 Inline arrays in the C# standard.
Struct initialization and default values
A variable of a struct type directly contains the data for that struct. This direct data storage creates a distinction between an uninitialized struct, which has its default value, and an initialized struct, which stores values set by constructing it. For example, consider the following code:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csParameterlessConstructor
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}As the preceding example shows, the default value expression ignores a parameterless constructor and produces the default value of the structure type. Structure-type array instantiation also ignores a parameterless constructor and produces an array populated with the default values of a structure type.
The most common situation where you see default values is in arrays or in other collections where internal storage includes blocks of variables. The following example creates an array of 30 TemperatureRange structures, each of which has the default value:
// All elements have default values of 0:
TemperatureRange[] lastMonth = new TemperatureRange[30];All of a struct's member fields must be definitely assigned when created because struct types directly store their data. The default value of a struct definitely assigns all fields to 0. All fields must be definitely assigned when a constructor is invoked. You initialize fields by using the following mechanisms:
- Add field initializers to any field or auto-implemented property.
- Initialize any fields or auto properties in the body of the constructor.
If you don't initialize all fields in a struct, the compiler adds code to the constructor that initializes those fields to the default value. A struct assigned to its default value is initialized to the 0-bit pattern. A struct initialized with new is initialized to the 0-bit pattern, followed by executing any field initializers and a constructor.
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csFieldInitializer
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}Every struct has a public parameterless constructor. If you write a parameterless constructor, it must be public. If a struct declares any field initializers, it must explicitly declare a constructor. That constructor need not be parameterless. If a struct declares a field initializer but no constructors, the compiler reports an error. Any explicitly declared constructor (with parameters, or parameterless) executes all field initializers for that struct. All fields without a field initializer or an assignment in a constructor are set to the default value. For more information, see the C# language specification—Constructors.
Beginning with C# 12, struct types can define a primary constructor as part of its declaration. Primary constructors provide a concise syntax for constructor parameters that can be used throughout the struct body, in any member declaration for that struct.
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:
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csSnippetWithoutNew
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
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})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
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)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
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; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}For the built-in value types, use the corresponding literals to specify a value of the type.
Limitations with the design of a structure type
Structs have most of the capabilities of a class type. There are some exceptions:
- 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.
- A constructor of a structure type must initialize all instance fields 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. Pass by value 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. Use the ref, out, in, or ref readonly method parameter modifiers to indicate that an argument must be passed by reference. Use ref returns to return a method result by reference. For more information, see Avoid allocations.
struct constraint
Use the struct keyword in the struct constraint to specify that a type parameter is a non-nullable value type. Both structure and enumeration types satisfy the struct constraint.
Conversions
For any structure type (except ref struct types), boxing and unboxing conversions exist to and from the System.ValueType and System.Object types. Boxing and unboxing conversions also exist between a structure type and any interface that it implements.
C# language specification
For more information, see the Structs section of the C# language specification, specifically the following clauses:
- Readonly structs
- Readonly instance members
- Parameterless struct constructors
- Allow
withexpression on structs - Record structs
You can also read about Auto default structs in the C# language specification.