Structure types (C# reference)

A structure type (or struct type) is a value type that can encapsulate data and related functionality. 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. For example, .NET uses structure types to represent a number (both integer and real), a Boolean value, a Unicode character, a time instance. If you're focused on the behavior of a type, consider defining a class. Class types have reference semantics. That is, a variable of a class type contains a reference to an instance of the type, not the instance itself.

Because structure types have value semantics, we recommend you to define immutable structure types.

readonly struct

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; }
    public double Y { get; }

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

All data members of a readonly struct must be read-only as follows:

  • Any field declaration must have the readonly modifier
  • Any property, including auto-implemented ones, must be read-only

That guarantees that no member of a readonly struct modifies the state of the struct.

Note

In a readonly struct, a data member of a mutable reference type still can mutate its own state. For example, you cannot replace a List<T> instance, but you can add new elements to it.

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 cannot declare a parameterless constructor. Every structure type already provides an implicit parameterless constructor that produces the default value of the type.

  • You cannot 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 cannot inherit from other class or structure type and it cannot be the base of a class. However, a structure type can implement interfaces.

  • You cannot declare a finalizer within a structure type.

Instantiation of a structure type

In C#, you must initialize a declared variable before it can be used. Because a structure-type variable cannot 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.

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.

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. Use the ref, out, or in 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 Write safe and efficient C# code.

Conversions

For any structure type, 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# language specification

For more information, see the Structs section of the C# language specification.

For more information about readonly structs, see the feature proposal note.

See also