2010-03-08 33 views
23

Önceki deneyimlerimden, null örneğinde uzantı yöntemlerini çağırmanın tamamen yasal olduğu (belki de önerilmez) olduğu izlenimindeydim. Yani C#, bu kod derlenmiş ve çalışan: AncakBu uzantı yöntemi neden VB.NET'te bir NullReferenceException kullanıyor?

// code in static class 
static bool IsNull(this object obj) { 
    return obj == null; 
} 

// code elsewhere 
object x = null; 
bool exists = !x.IsNull(); 

, ben sadece benim geliştirme ekibinin diğer üyeleri için bir araya örnek kod biraz paketi koyarak edildi (biz sadece ve ben ettik .NET 3.5 yükseltilmiş Ekibimiz tarafından sunulan bazı yeni özelliklerin hızlandırılması görevini üstlendik.) ve ben 'un yukarıdaki kodun VB.NET eşdeğeri olduğunu düşündüğümü yazdım, sadece bir NullReferenceException atar . Ben bir örnek yöntemi denir sanki

' code in module ' 
<Extension()> _ 
Function IsNull(ByVal obj As Object) As Boolean 
    Return obj Is Nothing 
End Function 

' code elsewhere ' 
Dim exampleObject As Object = Nothing 
Dim exists As Boolean = Not exampleObject.IsNull() 

ayıklayıcı, orada durur: Yazdığım kod bu oldu. Yanlış bir şey yapıyorum mu (örneğin, C# ve VB.NET arasındaki uzantı yöntemini tanımladığım şekilde bazı ince farklar var mı?)? Aslında C# 'de yasal olsa da, VB.NET'te boş bir örnek üzerinde bir uzantı yöntemini çağırmak için yasal değil mi? (Bunun bir dile özgü bir şeyin aksine bir .NET olayı olduğunu düşünebilirdim, ama belki de yanılmışımdır.)

Bunu bana açıklayan var mı?

+1

ısnull yöntemi sadece bir örnektir mı yoksa aslında x.IsNull kullanmak istiyorsunuz vardır() 'x Nothing' veya 'x == null' yerine? – jrummell

+0

@jrummell: Bu sadece bir örnek. Daha önce de belirttiğim gibi, bazı ekip üyelerim için uzatma yöntemlerinin nasıl çalıştığını göstermek için örnek bir kod yazıyordum. Bu yöntemin, "Bunu önerememesine rağmen, bunu aslında uzantı yöntemleriyle yapabilirsiniz." Başlıklı bir yorum eklemeyi planladım - sadece kaputun altında bir uzantı yönteminin gerçekten sadece statik olduğunu göstermek için) yöntem. Ama sonra beni şaşırttığını VB'de yapamadığımı keşfettim. –

+1

Daha önce de bulunduğumuz gibi, bu sizin gibi geç bağlama desteğidir ... (VAR) VB'nin geç bağlama için böyle bir desteği olduğunu fark etmedim, bunun VB6 ile uyumluluk olduğunu düşünüyorum. Kısacası, eğer diğer geliştiriciler için bazı standartlar/eğitimler vermek istiyorsanız, Seçenek Strict'i görevlendirmek isteyebilirsiniz. Elbette YMMV. –

cevap

13

Nesne türünü VB.NET'te genişletemezsiniz.

Esas olarak, uzatma yöntemleri statik "Nesne" olarak yazıldığında herhangi ifadenin kapalı çağrılacak izin vermez. Bu, uzatma yöntemleriyle kırılmadan yazmış olabileceğiniz herhangi bir geç bağlı kodun engellenmesi için gerekliydi.

Referans:

+0

Ah, bu biraz anlam ifade etse de ... sürekli olarak rahatsızım ama C#/VB arasındaki farklılıklar/tutarsızlıklar. Bağlantılı makalelerden alınacak anahtar sözcükler; "nesneyi belirttiğinizde," bir nesneyi * başka * bir şeyden alır "anlamına gelir. Awesome. 8-) –

+0

@roygbiv: VB.NET'te çok sık kodlamayan biri olarak, dürüst bir şekilde geç kalmam. Bağlantıda ele alınanlar gibi bağlanan yöntem çağrıları bile mümkün olmuştur (VB.NET'in geç bağlama yeteneklerinin önemli ölçüde daha küçük olduğunu tahmin etmiş olurdum.) Bana yeni bir şeyler öğrettiğin için ve düşündüğüm şeylere ilk vurduğun için teşekkürler. Burada "doğru" cevabı var: –

+1

@DanTao: Keşke VB.NET'in bir "System.Object" değişkeninin bir değişken olarak bildirilmesini ve basitçe 'System.Object' temel türü olan bir sınıf referansı olarak davranmasını isterdim. Nesne ile ilişkili özel işlem olmaksızın. – supercat

0

Sorun, nesnenin boş olması gibi görünüyor. Ayrıca , aşağıdakilerden gibi bir şey denerseniz Dize ısnull

Dim exampleObject As Object = "Test" 
Dim text As String = exampleObject.IsNull() 

Sana exampleObject içine koyarak ne olursa olsun değer düşünmek denilen bir uzantısı yöntemi olmadığını söyleyerek istisna alırsınız, çerçeve ne tür bilir bu.

cevap aşağıda System.Object uzatılır duruma özgü gözüküyor: Ben şahsen VB aynı zamanda

8

Güncelleme CSharp ibaret değilim Nesne sınıfına uzantıları yöntemleri, önleyeceğini. Diğer sınıfları genişletirken VB'de NullReferenceException yoktur.

VB Nesne üzerinde tanımlı uzatma yöntemleri çağırmak için izin verir, fakat değişken statik nesne olarak yazılan değil sadece ise:

Bu davranış Connect issue bu belirtilen nedenle tasarım gereğidir.

nedeni VB de geç bağlama destekler ve Nesne olarak bildirilen bir değişkenin kapalı bir çağrı yaparken biz uzatma yöntemine bağla eğer, o zaman aramak için çalışıyoruz olsun veya olmasın olacağına dair belirsizliklerin olası olmasıdır Aynı ada sahip bir uzantı yöntemi veya farklı bir geç bağlanmış yöntemi.

Teorik biz Sıkı Açıkken bu izin verebilir, ancak sıkı seçeneğinin ilkelerinden biri o kodunuzun semantiğini değişmez gerektiğidir. Bu izin verildiyse, Seçeneği Sıkı ayarını değiştirerek farklı yöntemle sessiz bir yeniden bağlanmaya neden olabilir, bu da farklı çalışma zamanı davranışına neden olur.

Örnek:

Imports System.Runtime.CompilerServices 

Module Extensions 
    <Extension()> _ 
    Public Function IsNull(ByVal obj As Object) As Boolean 
     Return obj Is Nothing 
    End Function 

    <Extension()> _ 
    Public Function IsNull(ByVal obj As A) As Boolean 
     Return obj Is Nothing 
    End Function 

    <Extension()> _ 
    Public Function IsNull(ByVal obj As String) As Boolean 
     Return obj Is Nothing 
    End Function 

End Module 

Class A 
End Class 

Module Module1 

    Sub Main() 
     ' works 
     Dim someString As String = Nothing 
     Dim isStringNull As Boolean = someString.IsNull() 

     ' works 
     Dim someA As A = Nothing 
     Dim isANull As Boolean = someA.IsNull() 

     Dim someObject As Object = Nothing 
     ' throws NullReferenceException 
     'Dim someObjectIsNull As Boolean = someObject.IsNull() 

     Dim anotherObject As Object = New Object 
     ' throws MissingMemberException 
     Dim anotherObjectIsNull As Boolean = anotherObject.IsNull() 
    End Sub 

End Module 

Aslında, VB derleyici sizin değişken statik Object olarak yazıldığında durumunda bir geç bağlama çağrıyı oluşturur:

.locals init ([0] object exampleObject, [1] bool exists) 
    IL_0000: ldnull 
    IL_0001: stloc.0 
    IL_0002: ldloc.0 
    IL_0003: ldnull 
    IL_0004: ldstr  "IsNull" 
    IL_0009: ldc.i4.0 
    IL_000a: newarr  [mscorlib]System.Object 
    IL_000f: ldnull 
    IL_0010: ldnull 
    IL_0011: ldnull 
    IL_0012: call  
    object [Microsoft.VisualBasic]Microsoft.VisualBasic. 
     CompilerServices.NewLateBinding::LateGet(
     object, 
     class [mscorlib]System.Type, 
     string, 
     object[], 
     string[], 
     class [mscorlib]System.Type[], 
     bool[]) 
    IL_0017: call  object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::NotObject(object) 
    IL_001c: call  bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToBoolean(object) 
    IL_0021: stloc.1 
+0

Acaba - C# dilinde yazılmış bir kütüphanede iseler C# yolunu uzatma yöntemlerini çağırıyor mu? –

+0

ve @Joel: Sadece bunu test ettim - uzantı yöntemini bir C# kitaplığında, VB'den aramalı. VB kodu hala bir "NullReferenceException" attı. Görünüşe göre Gareth bir şeye benziyor: Bu sorun sadece uzatma yöntemi, daha spesifik olan bir şeye karşı 'System.Object' için uygulandığında var. –

+0

Gerçekten de, işlev beklediği türde değil, uzantı yöntemini çağırmaya çalıştığınız nesnenin türü. Yani, IsNull (Object olarak ByVal Obj) Dim A As String ile çalışır ... A.Sadece iyi, A bile hiçbir şey değildir. roygbiv'in neden olduğuyla ilgili bağlantıları var gibi görünüyor. –

3

O ile ilginç bir şey gibi görünüyor Nesne, muhtemelen VB'de bir hata veya derleyicide bir sınırlama, yorum yapmak için onun Holiness Jon Skeet'e ihtiyaç duyabilir! Temel olarak, NullReferenceException'a neden olan uzantı yöntemini çağırmak yerine, IsNull çağrısını çalışma zamanında bağlamayı denemeye çalışıyor görünmektedir. Üste | Seçenek Strict'i açarsanız, bunu tasarım zamanında kırmızı dalgalı çizgilerle görürsünüz.

Örneğin Nesnenin kendisi dışındaki bir şeye değiştirilmesi, söz konusu türün değeri Hiçbir şey olmasa bile örnek kodunuzun çalışmasına izin verir.

+0

+1. Uzantı yöntemi, Hiçbir şey yalnızca tür Nesne değilse kullanılmasına izin verir. Yani, çalışma zamanında nesnenin doğası ile bağlantılı gibi görünüyor. –

+0

Ha, vay ... şimdi bu garip. –

İlgili konular