ref return 和 ref local
Ref 返回和 ref locals 對於操作和返回對記憶體塊的引用非常有用,而不是在不訴諸不安全指標的情況下複製記憶體。
參考返回
public static ref TValue Choose<TValue>(
Func<bool> condition, ref TValue left, ref TValue right)
{
return condition() ? ref left : ref right;
}
有了這個,你可以通過引用傳遞兩個值,其中一個值根據某些條件返回:
Matrix3D left = …, right = …;
Choose(chooser, ref left, ref right).M20 = 1.0;
參考本地
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
不安全的參考操作
在 System.Runtime.CompilerServices.Unsafe
中,已經定義了一組不安全的操作,它們允許你操作 ref
值,就好像它們是指標一樣。
例如,將記憶體地址(ref
)重新解釋為不同的型別:
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]);
但是,在執行此操作時請注意位元組順序 ,例如,如果需要,請檢查 BitConverter.IsLittleEndian
並相應地處理。
或者以不安全的方式迭代陣列:
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);
或類似的 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);
另外,可以檢查兩個 ref
值是否相同,即相同的地址:
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]));