C# Language ref retour et ref local


Exemple

Les retours Ref et les sections locales de référence sont utiles pour manipuler et renvoyer des références à des blocs de mémoire au lieu de copier la mémoire sans avoir recours à des pointeurs non sécurisés.

Ref Return

public static ref TValue Choose<TValue>(
    Func<bool> condition, ref TValue left, ref TValue right)
{
    return condition() ? ref left : ref right;
}

Avec cela, vous pouvez passer deux valeurs par référence, l'une d'entre elles étant renvoyée en fonction de certaines conditions:

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

Opérations de référence non sécurisées

Dans System.Runtime.CompilerServices.Unsafe un ensemble d'opérations dangereuses ont été définies pour vous permettre de manipuler les valeurs ref comme s'il s'agissait de pointeurs.

Par exemple, réinterpréter une adresse mémoire ( ref ) sous un autre 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]);

Faites attention à la finalité lorsque vous faites cela, cependant, par exemple, vérifiez BitConverter.IsLittleEndian si nécessaire et gérez en conséquence.

Ou itérer sur un tableau d'une manière dangereuse:

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);

Ou la Subtract similaire:

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);

De plus, on peut vérifier si deux valeurs ref sont identiques, c’est-à-dire même adresse:

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]));

Liens

Question de Roslyn Github

System.Runtime.CompilerServices.Unsafe sur github