SORU
29 HAZİRAN 2010, Salı


Neden bu=! check boş?

Bazen biraz zaman geçirmek için seviyorum .NET sadece perde arkasında bazı nasıl uygulandığını görmek için kod. Reflektör) String.Equals yöntemi bakarken bu taş sendeledi.

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 
}

null karşı this kontrol gerekçesi nedir? Bu muhtemelen yakalandı ve şimdi kaldırdınız ki başka bir amaç yok sanıyorum.

CEVAP
29 HAZİRAN 2010, Salı


Sonunda aradığını varsayıyorum .NET 3.5 uygulama? Bu inanıyorum .NET 4 Uygulama biraz farklı.

Ancak, olası bile sanal örnek yöntemleri olmayan hemen hemen diyoruz çünkü bu bir sinsi bir şüphe varnull bir referans. Mümkün IL. null.Equals(null) çağıran bazı IL üretmek miyim, bir bakayım.

EDİT: Tamam, İşte bazı ilginç kod:

.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

Aşağıdaki C derleme olarak bunu aldım# kod:

using System;

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

    }
}

... ve sonra sökülmesi ile 19* *ve düzenleme. Bu satırı not:

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

Aslında, o call yerine callvirt.

Biz yeniden birleştirmek zaman ne olacak? Peki, ile .NET 4.0 bu elde ederiz

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

Hmm. Ne hakkında .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()

Şimdi daha ilginç... açıkça normalde tahmin edemezdik EqualsHelper girmeye başardık.

Dize kadar... hadi referans eşitlik kendimizi uygulamak, null.Equals(null) doğru dönmek alabiliriz olup olmadığını görmek için deneyin:

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;
    }
}

Daha önce olduğu gibi aynı prosedür, call, tekrar kurmak callvirt demonte değiştirmek ve true izle. baskı

Başka başvurular yanıtlar rağmen this C question diyoruz çünkü burada daha dolambaçlı... olduğumuzu unutmayınsanalyöntem-neredeyse olmayan. Hatta C /CLİ derleyici sanal bir yöntem için callvirt kullanır normalde. Diğer bir deyişle, bu durumda bence this boş olmak için tek yolu elle IL yazmaktır.


EDİT: bir şey fark ettim... aslında doğru yöntem aramadımyaküçük bir örnek program. İşte ilk durumda: çağrı

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

işte bu da ikincisi: Ara

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

İlk durumda, bendemek35 ** ve ikinci arayacağımdemekTest::Equals(object) Ara. Bu üç şey görebiliriz:

  • Aşırı dikkatli olmak gerekir.
  • C# derleyicisi yaydığı için çağırırdeclarersanal yöntemi - en Belirli değilgeçersiz kılarsanal yöntemi. IIRC, VB ters şekilde çalışır
  • object.Equals(object) "" referans . bu bir boş karşılaştırmak için mutlu

Eğer C çıkış konsolu biraz eklerseniz# override, farkı görebilirsiniz - IL açıkça, bu şekilde aradığım için değiştirmediğiniz sürece denilen olmayacak:

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

Yani, biz vardır. Null referanslar örnek yöntemleri eğlenceli ve istismar.

Eğer bu güne kadar yaptık, ayrıca IL how value types can declare parameterless constructors... hakkında blog yazısı bakmak isteyebilirsiniz.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • alexis gillis

    alexis gilli

    23 HAZİRAN 2011
  • HowToBasic

    HowToBasic

    8 Aralık 2011
  • RiceBunny

    RiceBunny

    16 ŞUBAT 2006