Domanda

Per esperienza precedente avevo avuto l'impressione che è perfettamente legale (anche se forse non consigliabile) per chiamare metodi di estensione su un'istanza null. Quindi, in C #, questo codice viene compilato ed eseguito:

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

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

Comunque, stavo solo mettendo insieme una piccola suite di codice di esempio per gli altri membri del mio team di sviluppo (siamo appena trasferiti in .NET 3.5 e sono stato assegnato il compito di ottenere la squadra fino a velocità su alcune delle a nostra disposizione le nuove funzioni), e ho scritto quello che i Riflessione era l'equivalente VB.NET del codice di cui sopra, solo per scoprire che in realtà getta una NullReferenceException. Il codice che ho scritto è stato questo:

' 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()

Il debugger si ferma proprio lì, come se avessi chiamato un metodo di istanza. Sto facendo qualcosa di sbagliato (per esempio, c'è qualche sottile differenza nel modo in cui ho definito il metodo di estensione tra C # e VB.NET)? E 'in realtà non legale per chiamare un metodo di estensione su un'istanza nulla in VB.NET, anche se è legale in C #? (Avrei pensato che questo era una cosa .NET al contrario di una cosa specifica lingua, ma forse mi sbagliavo.)

Qualcuno può spiegare questo a me?

È stato utile?

Soluzione

Non è possibile estendere il tipo di oggetto in VB.NET.

  
    

Soprattutto, non permettiamo i metodi di estensione di essere chiamato fuori di ogni espressione che viene digitato in modo statico come "Oggetto". Ciò è stato necessario per evitare qualsiasi codice di ritardo legato esistente potrebbe essere scritto da essere rotto da metodi di estensione.

  

Riferimento:

Altri suggerimenti

Aggiornamento:

La risposta qui sotto sembra essere specifico per il caso del System.Object è esteso. Quando si estende altre classi non v'è alcuna NullReferenceException in VB.

Questo comportamento legato alla progettazione per la ragione indicata in questo Collegare problema :

  

VB consente di chiamare metodi di estensione definito su oggetti, ma solo   se la variabile non è staticamente   digitato come oggetto.

     

Il motivo è VB supporta anche late-binding, e se ci si legano a un   metodo di estensione quando si effettua una chiamata   fuori una variabile dichiarata come oggetto,   allora è ambiguo o meno   si sta cercando di chiamare un interno   metodo o un altro tardo-bound   metodo con lo stesso nome.

     

In teoria potremmo permettere questo con Strict On, ma uno dei   principi di Option Strict è che   non dovrebbe cambiare la semantica di   il tuo codice. Se questo è stato permesso poi   cambiare l'impostazione Option Strict   potrebbe causare una rilegatura in silenzio per un   metodo diverso, con conseguente totalmente   comportamento runtime diverso.

Esempio:

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

In realtà, il compilatore VB crea una chiamata tardiva in caso il vostro variabile è staticamente tipizzato come Object:

.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

Sembra essere qualcosa di eccentrico con oggetto, forse un bug in VB o una limitazione nel compilatore, potrebbe essere necessario Sua Santità Jon Skeet commento!

In sostanza sembra essere cercando di legare in ritardo la chiamata IsNull in fase di esecuzione, piuttosto che chiamare il metodo di estensione, che fa sì che il NullReferenceException. Se si attiva l'opzione Strict vedrete questo in fase di progettazione con i ghirigori rossi.

La modifica exampleObject a qualcosa di diverso oggetto stesso permetterà il vostro codice di esempio al lavoro, anche se il valore di tale tipo è nulla.

Sembra che il problema è che l'oggetto è nullo. Inoltre, se si cerca qualcosa di simile a quanto segue, si otterrà un'eccezione dicendo che String non ha un metodo di estensione chiamato IsNull

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

Credo che qualsiasi valore che si sta mettendo in exampleObject, il quadro sa che tipo è. Io personalmente evitare estensioni metodi sulla classe Object, non solo in VB, ma anche in CSharp

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top