ref return and ref local
suggest changeRef returns and ref locals are useful for manipulating and returning references to blocks of memory instead of copying memory without resorting to unsafe pointers.
Ref Return
public static ref TValue Choose<TValue>(
Func<bool> condition, ref TValue left, ref TValue right)
{
return condition() ? ref left : ref right;
}
With this you can pass two values by reference with one of them being returned based on some condition:
Matrix3D left = …, right = …;
Choose(chooser, ref left, ref right).M20 = 1.0;
Ref Local
public static ref int Max(ref int first, ref int second, ref int third)
{
ref int max = first > second ? ref first : ref second;
return max > third ? ref max : ref third;
}
…
int a = 1, b = 2, c = 3;
Max(ref a, ref b, ref c) = 4;
Debug.Assert(a == 1); // true
Debug.Assert(b == 2); // true
Debug.Assert(c == 4); // true
Unsafe Ref Operations
In System.Runtime.CompilerServices.Unsafe
a set of unsafe operations have been defined that allow you to manipulate ref
values as if they were pointers, basically.
For example, reinterpreting a memory address (ref
) as a different type:
byte[] b = new byte[4] { 0x42, 0x42, 0x42, 0x42 };
ref int r = ref Unsafe.As<byte, int>(ref b[0]);
Assert.Equal(0x42424242, r);
0x0EF00EF0;
Assert.Equal(0xFE, b[0] | b[1] | b[2] | b[3]);
Beware of endianness when doing this, though, e.g. check BitConverter.IsLittleEndian
if needed and handle accordingly.
Or iterate over an array in an unsafe manner:
int[] a = new int[] { 0x123, 0x234, 0x345, 0x456 };
ref int r1 = ref Unsafe.Add(ref a[0], 1);
Assert.Equal(0x234, r1);
ref int r2 = ref Unsafe.Add(ref r1, 2);
Assert.Equal(0x456, r2);
ref int r3 = ref Unsafe.Add(ref r2, -3);
Assert.Equal(0x123, r3);
Or the similar Subtract
:
string[] a = new string[] { "abc", "def", "ghi", "jkl" };
ref string r1 = ref Unsafe.Subtract(ref a[0], -2);
Assert.Equal("ghi", r1);
ref string r2 = ref Unsafe.Subtract(ref r1, -1);
Assert.Equal("jkl", r2);
ref string r3 = ref Unsafe.Subtract(ref r2, 3);
Assert.Equal("abc", r3);
Additionally, one can check if two ref
values are the same i.e. same address:
long[] a = new long[2];
Assert.True(Unsafe.AreSame(ref a[0], ref a[0]));
Assert.False(Unsafe.AreSame(ref a[0], ref a[1]));
Links
System.Runtime.CompilerServices.Unsafe on github