Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
You can use the ref modifier in the declaration of a structure type. Instances of a ref struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of ref struct types as follows:
- A
ref structcan't be the element type of an array. - A
ref structcan't be a declared type of a field of a class or a non-ref struct. - A
ref structcan't be boxed to System.ValueType or System.Object. - A
ref structvariable can't be captured in a lambda expression or a local function. - Before C# 13,
ref structvariables can't be used in anasyncmethod. Beginning with C# 13, aref structvariable can't be used in the same block as theawaitexpression in anasyncmethod. However, you can useref structvariables in synchronous methods, for example, in methods that return Task or Task<TResult>. - Before C# 13, a
ref structvariable can't be used in iterators. Beginning with C# 13,ref structtypes andreflocals can be used in iterators, provided they aren't in code segments with theyield returnstatement. - Before C# 13, a
ref structcan't implement interfaces. Beginning with C# 13, arefstruct can implement interfaces, but must adhere to the ref safety rules. For example, aref structtype can't be converted to the interface type because that requires a boxing conversion. - Before C# 13, a
ref structcan't be a type argument. Beginning with C# 13, aref structcan be the type argument when the type parameter specifies theallows ref structin itswhereclause.
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;
}
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; }
}
In .NET, examples of a ref struct are System.Span<T> and System.ReadOnlySpan<T>.
ref fields
Beginning with C# 11, you can declare a ref field in a ref struct, as the following example shows:
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;
}
}
A ref field can have the null value. Use the Unsafe.IsNullRef<T>(T) method to determine if a ref field is null.
You can apply the readonly modifier to a ref field in the following ways:
readonly ref: You can ref reassign such a field with the= refoperator only inside a constructor or aninitaccessor. You can assign a value with the=operator at any point allowed by the field access modifier.ref readonly: At any point, you can't assign a value with the=operator to such a field. However, you can ref reassign a field with the= refoperator.readonly ref readonly: You can only ref reassign such a field in a constructor or aninitaccessor. At any point, you can't assign a value to the field.
The compiler ensures that a reference stored in a ref field doesn't outlive its referent.
The ref fields feature enables a safe implementation of types like System.Span<T>:
public readonly ref struct Span<T>
{
internal readonly ref T _reference;
private readonly int _length;
// Omitted for brevity...
}
The Span<T> type stores a reference through which it accesses the contiguous elements in memory. The use of a reference enables a Span<T> instance to avoid copying the storage it refers to.
The disposable pattern
You can define a disposable ref struct. To do that, ensure that a ref struct fits the disposable pattern. That is, it has an instance Dispose method that's accessible, parameterless, and has a void return type. You can use the using statement or declaration with an instance of a disposable ref struct.
Beginning with C# 13, you can also implement the IDisposable on ref struct types. However, overload resolution prefers the disposable pattern to the interface method. The compiler resolves to an IDisposable.Dispose method only when a suitable Dispose method isn't found.
Restrictions for ref struct types that implement an interface
These restrictions ensure that a ref struct type that implements an interface obeys the necessary ref safety rules.
- A
ref structcan't be converted to an instance of an interface it implements. This restriction includes the implicit conversion when you use aref structtype as an argument when the parameter is an interface type. The conversion results in a boxing conversion, which violates ref safety. Aref structcan declare methods as explicit interface declarations. However, those methods can be accessed only from generic methods where the type parameterallows ref structtypes. - A
ref structthat implements an interface must implement all instance interface members. Theref structmust implement instance members even when the interface includes a default implementation.
The compiler enforces these restrictions. If you write ref struct types that implement interfaces, each new update might include new default interface members. Until you provide an implementation for any new instance methods, your application won't compile. You can't provide a specific implementation for a static interface method with a default implementation.
Important
A ref struct that implements an interface includes the potential for later source-breaking and binary-breaking changes. The break occurs if a ref struct implements an interface defined in another assembly, and that assembly provides an update which adds default members to that interface.
The source-break happens when you recompile the ref struct: It must implement the new member, even though there's a default implementation.
The binary-break happens if you upgrade the external assembly without recompiling the ref struct type and the updated code calls the default implementation of the new method. The runtime throws an exception when the default member is accessed.
C# language specification
For more information, see the following sections of the C# language specification:
For more information about ref fields, see the Low-level struct improvements proposal note.