2012-04-25 14 views
5

Alguien tiene alguna idea de por qué esto no funciona (C# o VB.NET u otro lenguaje .NET no importa). Este es un ejemplo muy simplificado de mi problema (lo siento por VB.NET):Interesante comportamiento de la propiedad

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 

Si lo hace:

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

Usted se sorprenderá de los resultados. Imprimirá "Nada". Alguien tiene alguna idea de por qué no se imprime "Algo"

He aquí una prueba unitaria por sugerencia:

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 

Esto devuelve:

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

Me sorprende que 'value =" Something "' compile. Hmm parece que 'value' no es una palabra clave en VB.net, sino solo un parámetro normal, que explica que se compila. – CodesInChaos

+0

Es una cadena, no tiene que "Nuevo" al configurarlo – Denis

+1

@CodeInChaos en C# usted puede hacer 'value = null;' en un setter –

Respuesta

13

tu comentario:

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

llamadas fuera cuál es tu error En Visual Basic hay dos maneras de devolver algo de una función:

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

o

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

La mezcla de estos dos estilos es perfectamente legal, pero confuso y una mala práctica:

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

Como puede ver, está mezclando los dos estilos en el captador. Al establecer esa variable no se llama al colocador; informa al tiempo de ejecución que cuando el getter regrese, este es el valor que debería devolver. A continuación, anula ese valor con su declaración Return.

Si le duele cuando lo hace, entonces no haga eso.

+0

Estoy tratando de llamar al "setter" desde el "getter". Hago esto en C# todo el tiempo. ¿Hay algún problema con eso en VB.NET? – Denis

+1

@Denis Sí, lo hay. El ajuste [nombre de función/propiedad] = [algún valor] básicamente se asigna asignando un valor de retorno implícito, que se devuelve al final del método si ningún otro comando 'Return' está presente antes del final. –

+0

@Denis 1) ¿Por qué harías eso? 2) Parece que VB como pascal interpreta una asignación al nombre de la función como el ajuste del valor de retorno. * (Es sorprendente cómo un poco de tiempo con C# me hizo olvidar cómo se comportó Pascal.) * 3) Supongo que 'me.Property = bla' llamará al setter. – CodesInChaos

-3

Debido a que en realidad nunca ha inicializado la variable. Tendría que "configurar" la propiedad a nada para obtener realmente "Algo". Para solucionarlo probablemente debería establecer el valor predeterminado al declarar la variable interna

Private itsCustomTextFormatter As String = "Something" 
+0

No entiendo tu razonamiento. – CodesInChaos

+0

No estoy seguro de cómo es relevante – Denis

4

Funciona bien para mí en una prueba de unidad; aunque en C# (ver más abajo).

(después de algún juego)

Ah tiene! Es porque estás llamando al CustomTextFormatter = Nothing que, en el ámbito del Getter, solo está configurando el valor de retorno del método de acceso adjunto, en realidad no está activando el setter (si pones un punto de interrupción en tu setter, lo verás y lo depurarás). lo veré pasar justo encima).

Básicamente usted Realmente no debería estar haciendo este tipo de patrón de todos modos; no es la forma de devolver un valor de propiedad predeterminado. Esto sería mejor (o utilizar cualquiera que sea el equivalente al operador de C# ?? es):

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 

original de C# de prueba

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

ver mi prueba de la unidad VB.NET anterior a – Denis

+1

Me pregunto por qué el comportamiento es diferente para VB.NET y C#? – Denis

+0

@Denis - está bien así que lo primero que notamos es que no es .Net - es específico de VB o (más probablemente) específico de * su * código VB. Solo tenemos que descubrir por qué. –

Cuestiones relacionadas