检查 null 时,泛型函数是否将值类型隐式转换为对象? [英] Does a generic function implicitly cast value types to objects when checking for null?
问题描述
例如下面的代码展示了我的思路:
For example the following code demonstrates my line of thought:
class Program
{
static void Main(string[] args)
{
int i = 0;
IsNull(i); // Works fine
string s = null;
IsNull(s); // Blows up
}
static void IsNull<T>(T obj)
{
if (obj == null)
throw new NullReferenceException();
}
}
还有以下代码:
int i = 0;
bool b = i == null; // Always false
是否正在进行隐式对象转换?使得:
Is there an implicit object cast going on? such that:
int i = 0;
bool b = (object)i == null;
推荐答案
是的,obj
被编译器装箱了.这是为您的 IsNull
函数生成的 IL:
Yes, obj
gets boxed by the compiler. This is the IL generated for your IsNull
function:
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: brtrue.s IL_000e
IL_0008: newobj instance void [mscorlib]System.NullReferenceException::.ctor()
IL_000d: throw
IL_000e: ret
box
指令是转换发生的地方.
The box
instruction is where the casting happens.
编译器不知道关于 T
的任何特定内容,因此它必须假定它必须是 object
- .NET 中所有内容的基本类型;这就是为什么它装箱 obj
以确保可以执行空检查.如果您使用 类型约束,您可以向编译器提供更多信息T
.
The compiler doesn't know anything specific about T
so it must assume that it must be an object
- the base type of everything in .NET; this is why it boxes obj
to make sure that the null check can be performed. If you use a type constraint you can give more information to the compiler about T
.
例如,如果您使用 where T : struct
您的 IsNull
函数将不再编译,因为编译器知道 T
是一个值type 和 null 不是值类型的值.
For example, if you use where T : struct
your IsNull
function won't compile anymore because the compiler knows T
is a value type and null is not a value for value types.
装箱一个值类型实例总是返回一个有效的(非空)对象实例*,所以 IsNull
函数永远不会抛出一个值类型.如果您考虑一下,这实际上是正确的行为:数值 0
不是 null
- 值类型值不可能是 null
.
Boxing a value type instance always returns a valid (non-null) object instance*, so the IsNull
function would never throw for a value type. This is actually correct behavior if you think about it: the numeric value 0
is not null
- a value type value cannot possibly be null
.
在上面的代码中 brtrue.s
非常像 if(objref!=0)
- 它不检查对象的值(值类型装箱前的值),因为在检查时,它不是位于堆栈顶部的值:它是位于顶部的装箱对象实例.由于该值(它实际上是一个指针)是非空的,因此对 null
的检查永远不会返回为真.
In the code above brtrue.s
is very much like if(objref!=0)
- it doesn't check the value of the object (the value type value before boxing) because at the time of the check, it's not a value that's on top of the stack: it's the boxed object instance that's on top. Since that value (it's really a pointer) is non-null, the check for null
never comes back as true.
*Jon Hanna 在评论中指出,对于 default(Nullable<T>)
,此语句不正确,这是正确的 - 装箱此值返回 null
对于任何T
.
*Jon Hanna pointed out in a comment that this statement is not true for default(Nullable<T>)
which is correct - boxing this value returns null
for any T
.
这篇关于检查 null 时,泛型函数是否将值类型隐式转换为对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!