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.
Ref<T>
The Ref<T>
is a stack-only type that can store a reference to a value of a specified type. It is semantically equivalent to a ref T
value, with the difference that it can also be used as a type of field in another stack-only struct
type. It can be used in place of proper ref T
fields, which are currently not supported in C#.
Platform APIs:
Ref<T>
,ReadOnlyRef<T>
How it works
Note
Due to how it's implemented on different .NET Standard contracts, the Ref<T>
has some minor differences on .NET Standard 1.4 and .NET Standard 2.1 (and equivalent .NET Core runtimes). In particular, on .NET Standard 1.4 it can only be used to reference fields within an object, instead of arbitrary values pointed by a managed reference. This is because the underlying APIs being used on .NET Standard 1.4 don't have built-in support for the Span<T>
type.
Ref<T>
on .NET Standard 1.4
As mentioned before, on .NET Standard 1.4, Ref<T>
can only point to locations within a given object
. Consider the following code:
// Be sure to include this using at the top of the file:
using Microsoft.Toolkit.HighPerformance;
// Define a sample model
class MyModel
{
public int Number = 42;
}
var model = new MyModel();
// Create a Ref<T> pointing to the MyModel.Number field
Ref<int> byRef = new Ref<T>(model, ref model.Number);
// Modify the field indirectly
byRef.Value++;
Console.WriteLine(model.Number); // Prints 43!
Warning
The Ref<T>
constructor doesn't validate the input arguments, meaning that it is your responsibility to pass a valid object
and a reference to a field within that object. Failing to do so might cause the Ref<T>.Value
property to return an invalid reference.
Ref<T>
on .NET Standard 2.1
On .NET Standard 2.1, Ref<T>
can point to any ref T
value:
int number = 42;
// Create a Ref<int> pointing to 'number'
Ref<int> byRef1 = new Ref<int>(ref number);
// Modify 'number'
byRef1.Value++;
Console.WriteLine(number); // Prints 43!
Warning
This type comes with a few caveats and should be used carefully, as it can lead to runtime crashes if a Ref<T>
instance is created with an invalid reference. In particular, you should only create a Ref<T>
instance pointing to values that have a lifetime that is greater than that of the Ref<T>
in use. Consider the following snippet:
public static ref int GetDummyReference()
{
int number = 42;
Ref<int> byRef = new Ref<T>(ref number);
return ref byRef.Value;
}
This will compile and run fine, but the returned ref int
will be invalid (as in, it will not point to a valid location) and could cause crashes if it's dereferenced. It is your responsibility to track the lifetime of values being referenced by new Ref<T>
values.
Note
Although it is possible to create a Ref<T>
value wrapping a null
reference, by using the default(Ref<T>)
expression, the Ref<T>
type is not designed to be used with nullable references and does not include proper features to validate the internal reference. If you need to return a reference that can be set to null
, use the NullableRef<T>
and NullableReadOnlyRef<T>
types.
ReadOnlyRef<T>
The ReadOnlyRef<T>
is a stack-only type that mirrors Ref<T>
, with the exception that its constructor takes an in T
parameter (a readonly reference), instead of a ref T
one. Similarly, its Value
property has a ref readonly T
return type instead of ref T
.
Examples
You can find more examples in the unit tests.
.NET Community Toolkit