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