Closed
Description
Background and motivation
Note: supersedes #73608.
This issue tracks updating the signatures of all methods that can benefit from either the new ref readonly
parameters (see dotnet/csharplang#6010), as well as the additional flexibility from the compiler allowing changes in ref-ness for method parameters without it being a breaking change (also see speclet at dotnet/csharplang#7165). Needs Roslyn changes first.
API Proposal
namespace System
{
public static class Nullable
{
- public static ref readonly T GetValueRefOrDefaultRef<T>(in T? nullable) where T : struct;
+ public static ref readonly T GetValueRefOrDefaultRef<T>(ref readonly T? nullable) where T : struct;
}
public readonly ref struct ReadOnlySpan<T>
{
- public ReadOnlySpan(in T reference);
+ public ReadOnlySpan(ref readonly T reference);
}
}
namespace System.Runtime.CompilerServices
{
public static class Unsafe
{
- public static bool AreSame<T>(ref T left, ref T right);
+ public static bool AreSame<T>(ref readonly T left, ref readonly T right);
- public static ref T AsRef<T>(in T source);
+ public static ref T AsRef<T>(ref readonly T source);
- public static nint ByteOffset<T>(ref T origin, ref T target);
+ public static nint ByteOffset<T>(ref readonly T origin, ref readonly T target);
- public static void Copy<T>(void* destination, ref T source);
+ public static void Copy<T>(void* destination, ref readonly T source);
- public static void CopyBlock(ref byte destination, ref byte source, uint byteCount);
+ public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount);
- public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount);
+ public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount);
- public static bool IsAddressGreaterThan<T>(ref T left, ref T right);
+ public static bool IsAddressGreaterThan<T>(ref readonly T left, ref readonly T right);
- public static bool IsAddressLessThan<T>(ref T left, ref T right);
+ public static bool IsAddressLessThan<T>(ref readonly T left, ref readonly T right);
- public static bool IsNullRef<T>(ref T source);
+ public static bool IsNullRef<T>(ref readonly T source);
- public static T ReadUnaligned<T>(ref byte source);
+ public static T ReadUnaligned<T>(ref readonly byte source);
}
}
namespace namespace System.Runtime.InteropServices
{
public static class Marshal
{
- public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+ public static int QueryInterface(IntPtr pUnk, in Guid iid, out IntPtr ppv);
}
public static class MemoryMarshal
{
- public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length);
+ public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref readonly T reference, int length);
- public static unsafe void Write<T>(Span<byte> destination, ref T value) where T : struct;
+ public static unsafe void Write<T>(Span<byte> destination, in T value) where T : struct;
- public static unsafe bool TryWrite<T>(Span<byte> destination, ref T value) where T : struct;
+ public static unsafe bool TryWrite<T>(Span<byte> destination, in T value) where T : struct;
}
}
namespace System.Threading
{
public static class Volatile
{
- public static bool Read(ref bool location);
+ public static bool Read(ref readonly bool location);
- public static byte Read(ref byte location);
+ public static byte Read(ref readonly byte location);
- public static double Read(ref double location);
+ public static double Read(ref readonly double location);
- public static short Read(ref short location);
+ public static short Read(ref readonly short location);
- public static int Read(ref int location);
+ public static int Read(ref readonly int location);
- public static long Read(ref long location);
+ public static long Read(ref readonly long location);
- public static IntPtr Read(ref IntPtr location);
+ public static IntPtr Read(ref readonly IntPtr location);
- public static sbyte Read(ref sbyte location);
+ public static sbyte Read(ref readonly sbyte location);
- public static float Read(ref float location);
+ public static float Read(ref readonly float location);
- public static ushort Read(ref ushort location);
+ public static ushort Read(ref readonly ushort location);
- public static uint Read(ref uint location);
+ public static uint Read(ref readonly uint location);
- public static ulong Read(ref ulong location);
+ public static ulong Read(ref readonly ulong location);
- public static UIntPtr Read(ref UIntPtr location);
+ public static UIntPtr Read(ref readonly UIntPtr location);
- public static T Read<T>(ref T location) where T : class?;
+ public static T Read<T>(ref readonly T location) where T : class?;
}
public static class Interlocked
{
- public static ulong Read(ref ulong location);
+ public static ulong Read(ref readonly ulong location);
- public static long Read(ref long location);
+ public static long Read(ref readonly long location);
}
}
namespace System.Numerics
{
public static class Vector
{
- public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
+ public static Vector<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
- public static Vector<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+ public static Vector<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
}
}
namespace System.Runtime.Intrinsics
{
public static class Vector64
{
- public static Vector64<T> LoadUnsafe<T>(ref T source) where T : struct;
+ public static Vector64<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
- public static Vector64<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+ public static Vector64<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
}
public static class Vector128
{
- public static Vector128<T> LoadUnsafe<T>(ref T source) where T : struct;
+ public static Vector128<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
- public static Vector128<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+ public static Vector128<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
}
public static class Vector256
{
- public static Vector256<T> LoadUnsafe<T>(ref T source) where T : struct;
+ public static Vector256<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
- public static Vector256<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+ public static Vector256<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
}
public static class Vector512
{
- public static Vector512<T> LoadUnsafe<T>(ref T source) where T : struct;
+ public static Vector512<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
- public static Vector512<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+ public static Vector512<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
}
}
API Usage
For instance, easy QI with immediate values:
IntPtr pUnknown = GetPtr();
Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pUnknown, new Guid("3718BE5F-F5A1-40CF-AF09-C4ECFD858A47"), out IntPtr pObject));
Or, writing immediates into spans:
Span<byte> bytes = GetSpan();
MemoryMarshal.Write(bytes, 128UL);
Or, loading vectors from readonly spans directly:
ReadOnlySpan<int> span = GetSpan();
Vector128<int> vector = Vector128.LoadUnsafe(in span[0]);
There's of course lots more examples (see API changes above).