为什么要检查这个!= NULL? [英] Why check this != null?

查看:659
本文介绍了为什么要检查这个!= NULL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时候我想花一些时间在.NET code只是为了看看事情是如何在幕后执行。我偶然发现了这颗宝石,而在看 String.Equals 通过反射的方法。

Occasionally I like to spend some time looking at the .NET code just to see how things are implemented behind the scenes. I stumbled upon this gem while looking at the String.Equals method via Reflector.

C#

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(object obj)
{
    string strB = obj as string;
    if ((strB == null) && (this != null))
    {
        return false;
    }
    return EqualsHelper(this, strB);
}

IL

.method public hidebysig virtual instance bool Equals(object obj) cil managed
{
    .custom instance void System.Runtime.ConstrainedExecution.ReliabilityContractAttribute::.ctor(valuetype System.Runtime.ConstrainedExecution.Consistency, valuetype System.Runtime.ConstrainedExecution.Cer) = { int32(3) int32(1) }
    .maxstack 2
    .locals init (
        [0] string str)
    L_0000: ldarg.1 
    L_0001: isinst string
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: brtrue.s L_000f
    L_000a: ldarg.0 
    L_000b: brfalse.s L_000f
    L_000d: ldc.i4.0 
    L_000e: ret 
    L_000f: ldarg.0 
    L_0010: ldloc.0 
    L_0011: call bool System.String::EqualsHelper(string, string)
    L_0016: ret 
}

什么是推理检查?我必须假设有目的,否则这很可能会被捕获并除去了。

What is the reasoning for checking this against null? I have to assume there is purpose otherwise this probably would have been caught and removed by now.

推荐答案

我假设你正在寻找的.NET 3.5的实现?我相信,在.NET 4的实现略有不同。

I assume you were looking at the .NET 3.5 implementation? I believe the .NET 4 implementation is slightly different.

不过,我有一个鬼鬼祟祟的怀疑,这是因为它可以调用甚至是虚拟实例的方法非虚拟的的空引用的。可能在白细胞介素,那就是。我会看看我是否能产生一些白细胞介素这会叫 null.Equals(空)

However, I have a sneaking suspicion that this is because it's possible to call even virtual instance methods non-virtually on a null reference. Possible in IL, that is. I'll see if I can produce some IL which would call null.Equals(null).

编辑:好的,这里的一些有趣的code:

Okay, here's some interesting code:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  2
  .locals init (string V_0)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldnull
  IL_0005:  call instance bool [mscorlib]System.String::Equals(string)
  IL_000a:  call void [mscorlib]System.Console::WriteLine(bool)
  IL_000f:  nop
  IL_0010:  ret
} // end of method Test::Main

我通过编译下面的C#code得到这个:

I got this by compiling the following C# code:

using System;

class Test
{
    static void Main()
    {
        string x = null;
        Console.WriteLine(x.Equals(null));

    }
}

...然后用反汇编拆卸和编辑。注意这一行:

... and then disassembling with ildasm and editing. Note this line:

IL_0005:  call instance bool [mscorlib]System.String::Equals(string)

本来,这是 callvirt 而不是通话

所以,当我们重新组装会发生什么?那么,与.NET 4.0中我们得到这样的:

So, what happens when we reassemble it? Well, with .NET 4.0 we get this:

Unhandled Exception: System.NullReferenceException: Object
reference not set to an instance of an object.
    at Test.Main()

嗯。怎么样使用.NET 2.0?

Hmm. What about with .NET 2.0?

Unhandled Exception: System.NullReferenceException: Object reference 
not set to an instance of an object.
   at System.String.EqualsHelper(String strA, String strB)
   at Test.Main()

现在,更有趣......我们已经清楚地设法进入 EqualsHelper ,我们就不会正常的预期。

Now that's more interesting... we've clearly managed to get into EqualsHelper, which we wouldn't have normally expected.

串足够了...让我们来尝试实现引用相等自己,看看我们是否能得到 null.Equals(空)返回true:

Enough of string... let's try to implement reference equality ourselves, and see whether we can get null.Equals(null) to return true:

using System;

class Test
{
    static void Main()
    {
        Test x = null;
        Console.WriteLine(x.Equals(null));
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public override bool Equals(object other)
    {
        return other == this;
    }
}

相同的程序和以前一样 - 拆机,换 callvirt 通话,重新组装,然后看着它打印 ...

Same procedure as before - disassemble, change callvirt to call, reassemble, and watch it print true...

请注意,尽管另一个答案参考这个C ++的问题,我们再被更狡猾这里...因为我们调用的虚拟的方法非虚拟化。通常,即使是C ++ / CLI编译器将使用 callvirt 的虚方法。换句话说,我想在这个特殊的情况下,唯一的办法为空是手工编写的IL。

Note that although another answers references this C++ question, we're being even more devious here... because we're calling a virtual method non-virtually. Normally even the C++/CLI compiler will use callvirt for a virtual method. In other words, I think in this particular case, the only way for this to be null is to write the IL by hand.

编辑:我刚刚发现了一些......我本来就不是调用正确的方法的无论是我们的小示例程序的。下面是在第一种情况下的呼叫:

I've just noticed something... I wasn't actually calling the right method in either of our little sample programs. Here's the call in the first case:

IL_0005:  call instance bool [mscorlib]System.String::Equals(string)

下面是在第二个电话:

IL_0005:  call instance bool [mscorlib]System.Object::Equals(object)

在第一种情况下,我的意味着的调用 System.String ::等于(对象),并在第二,我的意味着的调用测试::等于(对象)。由此我们可以看到三件事情:

In the first case, I meant to call System.String::Equals(object), and in the second, I meant to call Test::Equals(object). From this we can see three things:

  • 您需要小心过载。
  • 在C#编译器发出调用的庄家的虚方法 - 不是最具体的虚方法的覆盖的。 IIRC,VB的工作方式恰好相反
  • 的Object.Equals(对象)很高兴来比较空this引用
  • You need to be careful with overloading.
  • The C# compiler emits calls to the declarer of the virtual method - not the most specific override of the virtual method. IIRC, VB works the opposite way
  • object.Equals(object) is happy to compare a null "this" reference

如果您增添几分控制台输出到C#改写的,你可以看到不同的 - 除非你改变IL显式调用它,这样就不会被称为:

If you add a bit of console output to the C# override, you can see the difference - it won't be called unless you change the IL to call it explicitly, like this:

IL_0005:  call   instance bool Test::Equals(object)

因此​​,有我们。乐趣和滥用对空引用实例方法。

So, there we are. Fun and abuse of instance methods on null references.

如果你走到今天这一步,你可能也想看看关于<一个我的博客文章href="http://msmvps.com/blogs/jon_skeet/archive/2008/12/10/value-types-and-parameterless-constructors.aspx">how值类型的可以的声明参数构造函数 ......在IL。

If you've made it this far, you might also like to look at my blog post about how value types can declare parameterless constructors... in IL.

这篇关于为什么要检查这个!= NULL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆