我做了一些ref关键字测试,有一个认为我无法理解:
static void Test(ref int a, ref int b)
{
Console.WriteLine(Int32.ReferenceEquals(a,b));
}
static void Main(string[] args)
{
int a = 4;
Test(ref a, ref a);
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
为什么显示此代码False?我知道这int是一个值类型,但在这里它应该传递对同一个对象的引用.
Yuv*_*kov 38
为什么显示此代码
False?
因为int a并且在你打电话时int b 被装箱object.ReferenceEquals.每个整数都装在一个object实例中.因此,您实际上是在比较两个盒装值之间的参考,这两个值明显不相等.
如果查看方法生成的CIL,您可以很容易地看到这个:
Test:
IL_0000: nop
IL_0001: ldarg.0 Load argument a
IL_0002: ldind.i4
IL_0003: box System.Int32
IL_0008: ldarg.1 Load argument b
IL_0009: ldind.i4
IL_000A: box System.Int32
IL_000F: call System.Object.ReferenceEquals
IL_0014: call System.Console.WriteLine
IL_0019: nop
IL_001A: ret
Run Code Online (Sandbox Code Playgroud)
通过使用可验证的CIL(例如@ leppie的答案)或unsafe代码,可以检查存储位置是否相等:
unsafe static void Main(string[] args)
{
int a = 4;
int b = 5;
Console.WriteLine(Test(ref a, ref a)); // True
Console.WriteLine(Test(ref a, ref b)); // False;
}
unsafe static bool Test(ref int a, ref int b)
{
fixed (int* refA = &a)
fixed (int* refB = &b)
{
return refA == refB;
}
}
Run Code Online (Sandbox Code Playgroud)
lep*_*pie 18
这不能直接在C#中完成.
但是,您可以在可验证的CIL中实现它:
.method public hidebysig static bool Test<T>(!!T& a, !!T& b) cil managed
{
.maxstack 8
ldarg.0
ldarg.1
ceq
ret
}
Run Code Online (Sandbox Code Playgroud)
测试
int a = 4, b = 4, c = 5;
int* aa = &a; // unsafe needed for this
object o = a, p = o;
Console.WriteLine(Test(ref a, ref a)); // True
Console.WriteLine(Test(ref o, ref o)); // True
Console.WriteLine(Test(ref o, ref p)); // False
Console.WriteLine(Test(ref a, ref b)); // False
Console.WriteLine(Test(ref a, ref c)); // False
Console.WriteLine(Test(ref a, ref *aa)); // True
// all of the above works for fields, parameters and locals
Run Code Online (Sandbox Code Playgroud)
笔记
这实际上并没有检查相同的引用,但更精细,因为它确保两者都是相同的"位置"(或从同一个变量引用).这是第三行返回false即使o == p返回true.然而,这种"位置"测试的有用性非常有限.