2012-04-25 11 views
5

Chiunque ha qualche idea del perché questo non funziona (C# o VB.NET o altro linguaggio .NET non importa). Questo è un esempio molto semplificato del mio problema (mi dispiace per VB.NET):Comportamento proprietà interessante

Private itsCustomTextFormatter As String 
    Public Property CustomTextFormatter As String 
     Get 
      If itsCustomTextFormatter Is Nothing Then CustomTextFormatter = Nothing 'thinking this should go into the setter - strangely it does not' 
      Return itsCustomTextFormatter 
     End Get 
     Set(ByVal value As String) 
      If value Is Nothing Then 
       value = "Something" 
      End If 
      itsCustomTextFormatter = value 
     End Set 
    End Property 

Se lo fai:

Dim myObj as new MyClass 
Console.WriteLine(myObj.CustomTextFormatter) 

Sarete sorpresi del risultato. Stamperà "Niente". Qualcuno ha qualche idea del perché non viene stampata "Something"

Ecco un test unitario per suggerimento:

Imports NUnit.Framework 

<TestFixture()> _ 
Public Class Test 
    Private itsCustomTextFormatter As String 
    Public Property CustomTextFormatter As String 
     Get 
      If itsCustomTextFormatter Is Nothing Then CustomTextFormatter = Nothing 'thinking this should go into the setter - strangely it does not' 
      Return itsCustomTextFormatter 
     End Get 
     Set(ByVal value As String) 
      If value Is Nothing Then 
       value = "Something" 
      End If 
      itsCustomTextFormatter = value 
     End Set 
    End Property 

    <Test()> 
    Public Sub Test2() 
     Assert.AreEqual("Something", CustomTextFormatter) 
    End Sub 
End Class 

Ciò restituisce:

Test2 : Failed 
    Expected: "Something" 
    But was: null 

at NUnit.Framework.Assert.That(Object actual, IResolveConstraint expression, String message, Object[] args) 
at NUnit.Framework.Assert.AreEqual(Object expected, Object actual) 
+0

Sono sorpreso che 'value =" Something "' compili. Hmm sembra che 'value' non sia una parola chiave in VB.net, ma solo un parametro normale, che spiega che compila. – CodesInChaos

+0

È una stringa, non è necessario "Nuovo" quando lo si imposta – Denis

+1

@CodeInChaos in C# si può fare 'value = null;' in un setter –

risposta

13

tuo commento:

'thinking this should go into the setter - strangely it does not'  

chiamate fuori qual è il tuo errore In Visual Basic ci sono due modi per restituire qualcosa da una funzione:

Function GetSomeValue() As String 
    Return "Hello" 
End Function 

o

Function GetSomeValue() As String 
    GetSomeValue = "Hello" 
End Function 

Mescolando questi due stili è perfettamente legale, ma confusione e una cattiva pratica:

Function GetSomeValue() As String 
    GetSomeValue = "Hello" ' I should return Hello... ' 
    Return "GoodBye"  ' ...or perhaps not. ' 
End Function 

Come puoi vedere, stai mescolando i due stili nel getter. L'impostazione di tale variabile non chiama il setter; informa il runtime che quando ritorna il getter, questo è il valore che dovrebbe restituire. Quindi si sostituisce tale valore con l'istruzione Return.

Se fa male quando lo fai, allora non farlo.

+0

Sto provando a chiamare il "setter" dal "getter". Lo faccio sempre in C#. C'è qualche problema con quello in VB.NET? – Denis

+1

@Denis Sì, c'è. L'impostazione [nome funzione/proprietà] = [qualche valore] sta essenzialmente assegnando solo l'assegnazione di un valore di ritorno implicito, che viene restituito alla fine del metodo se nessun altro comando 'Return' è presente prima della fine. –

+0

@Denis 1) Perché dovresti farlo? 2) Sembra che VB come Pascal interpreti un attributo al nome della funzione come impostazione del valore di ritorno. * (Incredibile come un po 'di tempo con C# mi ha fatto dimenticare come si comportava pascal.) * 3) Immagino che 'me.Property = bla' chiamerà il setter. – CodesInChaos

-3

Perché non hai mai realmente inizializzato la variabile. Dovresti "Impostare" la proprietà su nulla per ottenere effettivamente "Qualcosa". Per risolvere il problema probabilmente si dovrebbe impostare il valore predefinito quando si dichiara la variabile interna

Private itsCustomTextFormatter As String = "Something" 
+0

Non capisco il tuo ragionamento. – CodesInChaos

+0

Non so come sia pertinente – Denis

4

funziona bene per me in una prova di unità; anche se in C# (vedi sotto).

(dopo un po 'di gioco)

Ah ce l'ha! È perché stai chiamando CustomTextFormatter = Nothing che, nell'ambito di Getter, in realtà è solo impostando il valore di ritorno del metodo di accesso allegato - non sta effettivamente sparando al setter (se metti un breakpoint nel setter lo vedrai e lo debuggerai vedremo che passi proprio sopra).

Fondamentalmente si in realtà non dovrebbe fare comunque questo tipo di modello; non è il modo per restituire un valore di proprietà predefinito. Questo sarebbe meglio (o di utilizzare qualunque sia l'equivalente per l'operatore C# ?? è):

Public Property CustomTextFormatter As String 
    Get 
     If itsCustomTextFormatter Is Nothing Then 
      Return "Something" 
     End If 
     Return itsCustomTextFormatter 

    End Get 
    Set(ByVal value As String) 
     itsCustomTextFormatter = value 
    End Set 
End Property 

originale C# prova

private string _foo; 
    private string foo 
    { 
     get 
     { 
      if (_foo == null) 
       foo = null; 
      return _foo; 
     } 
     set 
     { 
      if (value == null) 
       value = "Something"; 
      _foo = value; 
     } 
    } 

    [TestMethod] 
    public void Test() 
    { 
     Assert.AreEqual("Something", foo); 
    } 
+0

vedere il mio test unità VB.NET sopra – Denis

+1

Mi chiedo perché il behvior è diverso per VB.NET e C#? – Denis

+0

@Denis - okay, la prima cosa che notiamo è che non è .Net - è specifico per VB o (più probabile) specifico per * il tuo * codice VB. Dobbiamo solo scoprire perché. –

Problemi correlati