2010-08-06 15 views

Respuesta

6

Las propiedades son [un par de métodos get y set] con una linda sintaxis para invocarlos que los hace parecer campos.

Los parámetros de salida pueden ser referencias a campos o 'campos' basados ​​en pila (es decir, locales).

En general, los idiomas no abordan esta brecha (y definitivamente no directamente por el modelo CLR e IL). (+1 en @Heinzi para referencias de trucos de VB)

+1

Se agradecería una justificación para el -1 (aparte del hecho de que la respuesta de @Mark Byers ha crecido para incorporar este ángulo desde su publicación inicial?) –

+1

@ Craig Johnston: Lo felicito por ver a través de la niebla de las respuestas y el debate provocó su pregunta aparentemente simple! –

+0

+1: Para esto correctamente, debería capturar un par de cierres para cada propiedad. En ese punto 'ref int i' ocultará algún código bastante complicado. . . pero solo cuando se pasa una propiedad. Gran diferencia entre desreferenciar un int y acarrear alrededor y usar pares de cierres. PD. No puedo rechazar votos sin comentarios. –

3

El argumento pasado a un parámetro de salida no puede ser una propiedad. Si intenta compilar su código, obtendrá un error de compilación.

A property, indexer or dynamic member access may not be passed as an out or ref parameter

La razón es que una propiedad no es en realidad el campo (que podría tener un campo de respaldo, pero no podría). Se trata de dos métodos llamados get_Foo y set_Foo. Consulte c# property and ref parameter, why no sugar? para obtener más explicaciones de por qué esto no funciona.

Código de ejemplo que da el error de compilación:

class Program 
{ 
    public int Foo { get; set; } 
    public void Bar(out int x) 
    { 
     x = 5; 
    } 
    void Run() 
    { 
     Bar(out Foo); // compile error 
    } 
    static void Main() 
    { 
     new Program().Run(); 
    } 
} 
4

No, usted no puede utilizar una propiedad como parámetro ref o out en C#, ya que el CLR no soporta esto. Pasar una variable de instancia debería funcionar bien.

Como una nota, VB.NET permite pasar propiedades y utiliza una técnica llamada "copiar de nuevo ByRef", como se explica en this MSDN blog entry.

+2

+1: Recomiendo encarecidamente no pasar propiedades byref en VB.Net, puede tener sorprendentes efectos secundarios, mejor si, como C#, no fue compatible. –

+2

@Binary: ¿tiene alguna evidencia/referencia para este reclamo? – CJ7

+0

@Craig: He añadido mi propia "respuesta" a continuación, con ejemplos de código VB que muestran lo que quiero decir http://stackoverflow.com/questions/3422078/c-can-out-parameters-in-functions-be-object- properties-variables/3424123 # 3424123 –

0

Puede usar el parámetro out con campos (o locales como ya se dijo).

4

No puede hacer esto con C#.
Puedes con VB.Net, pero considero que es una mala idea. El siguiente código y de salida muestran cómo lo hace y muestra por qué creo que es una mala idea, hasta el punto que me gustaría también VB.net no permitió que esta

Public Class MySimpleClass 
    Private _privateInt As Integer 
    Public PublicInt As Integer 

    Public Property PrivateInt() As Integer 
     Get 
      Return _privateInt 
     End Get 
     Set(ByVal value As Integer) 
      _privateInt = value 
     End Set 
    End Property 

    Public Sub MyNotifier() 
     Console.WriteLine("PublicInt {0} : PrivateInt {1} : Values are not the same", PublicInt, PrivateInt) 
    End Sub 

End Class 

Ahora llaman a esto de una sub principal, al igual que

Sub Main() 
    Dim sampleClass As New MySimpleClass 
    IterateAndUpdate(sampleClass.PrivateInt, sampleClass.PublicInt, AddressOf sampleClass.MyNotifier) 

    Console.WriteLine("Private {0} : Public {0} : values are the same ", sampleClass.PrivateInt, sampleClass.PublicInt) 
    Console.ReadKey() 
End Sub 

Sub IterateAndUpdate(ByRef anInt As Integer, ByRef anOtherInt As Integer, ByVal notifier As Action) 
    For i As Integer = 1 To 9 
     anInt = i 
     anOtherInt = i 
     notifier() 
    Next 
End Sub 

Esto da salida a

PublicInt 1 : PrivateInt 0 : Values are not the same
PublicInt 2 : PrivateInt 0 : Values are not the same
PublicInt 3 : PrivateInt 0 : Values are not the same
PublicInt 4 : PrivateInt 0 : Values are not the same
PublicInt 5 : PrivateInt 0 : Values are not the same
PublicInt 6 : PrivateInt 0 : Values are not the same
PublicInt 7 : PrivateInt 0 : Values are not the same
PublicInt 8 : PrivateInt 0 : Values are not the same
PublicInt 9 : PrivateInt 0 : Values are not the same
Private 9 : Public 9 : values are the same

se puede ver que el miembro PublicInt cuando pasó ByRef se actualiza inmediatamente en SampleClass, poner elexpuesto como propiedad solo se actualiza después de que finaliza el método IterateAndUpdate.

Por lo tanto, se obtiene un comportamiento marcadamente diferente de exactamente la misma convención de llamada, y depende de cómo se ha implementado el elemento pasó (que no es en absoluto evidente mirando la llamada a IterateAndUpdate.
El potencial de ocultar errores, o tienen pequeños cambios cambian el comportamiento esperado es suficiente para que yo deseo esta "característica" que no existía.

en mi opinión esto no funciona correctamente, por lo que debe ser o bien
a) fijo, que tomaría un esfuerzo considerable para el equipo del compilador, y posiblemente introduzca cambios de rotura
o
b) No funciona en absoluto

+1

+1, análisis interesante. – Heinzi

Cuestiones relacionadas