来自https://msdn.microsoft.com/en-us/library/bb297966(v=vs.110).aspx
[ComVisibleAttribute(false)]
public static T CompareExchange<T>(
ref T location1,
T value,
T comparand
)
where T : class
和
NullReferenceException The address of location1 is a null pointer.
但是当我对location1
使用空引用时,我没有收到任何错误:
class A { }
class Program
{
static void Main(string[] args)
{
A dest = null;
A src = new A();
// If dest is null, then replace with src.
Interlocked.CompareExchange(ref dest, src, null);
}
}
这样做可以吗?是否存在将NullReferenceException
放入更高版本的.NET中的危险?
答案 0 :(得分:4)
这里的文档有误导性,因为location1
不能是null
,因为在C#中它必须始终引用现有变量。所以,是的,如果location1
已经src
并且#{1}}已经location1
,那么就可以将null
(当前包含null)设置为location1
34。
实际上因为NullReferenceException
必须是引用,所以不可能在C#中传递空引用,尽管它可以(并且有效)将引用传递给null的东西,所以这个函数永远不会抛出null
。
我怀疑这取决于从Win32 api移植的文档,您必须将指针传递给读取/写入变量的位置,在此处传递EntryQuery::create()->joinWith('Company')->joinWith("User")
将是错误的。
答案 1 :(得分:1)
正如另一个答案所说,让变量包含null
是完全可以的 - 它是关于对变量的引用是null
,而不是发生在C#或大多数其他托管语言中。
那就是说,你可以让Interlocked.CompareExchange
通过直接从IL工作来抛出NullReferenceException
。但即使在那里,如果你想保持在可管理的,可验证的代码领域,你也必须变得棘手:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init ([0] int32& x) // x is initialized to null
ldloc.0
ldc.i4.1
ldc.i4.2
call int32 [mscorlib]System.Threading.Interlocked::CompareExchange(
int32&, int32, int32)
pop
ret
}
此代码将通过验证,但它会在运行时抛出NullReferenceException
。堆栈跟踪实际上不会显示Interlocked.CompareExchange
,因为JIT编译器会将其内联到单个lock cmpxchg
指令。
正如@Sean正确指出的那样,这不应该证明文档说该方法可能抛出NullReferenceException
,因为这种方法可以用来破坏任何函数ref
或{{ 1}}参数。例如,如果“out
的地址为result
”,则Int32.TryParse
不会记录它可以抛出NRE,我们也不会指望它。在涉及引用时,隐式期望托管代码表现良好。