Este es un caso de abstracción con fugas. Una propiedad es en realidad un método, los descriptores de acceso get y set para un indexador se compilan en los métodos get_Index () y set_Index. El compilador hace un trabajo estupendo ocultando ese hecho, automáticamente traduce una asignación a una propiedad al método set_Xxx () correspondiente, por ejemplo.
Pero esto se arruina cuando pasa un parámetro de método por referencia. Eso requiere que el compilador JIT pase un puntero a la ubicación de memoria del argumento pasado. El problema es que no hay uno, asignar el valor de una propiedad requiere llamar al método setter. El método llamado no puede diferenciar entre una variable pasada y una propiedad pasada y, por lo tanto, no puede saber si se requiere una llamada al método.
Es de destacar que esto realmente funciona en VB.NET. Por ejemplo:
Class Example
Public Property Prop As Integer
Public Sub Test(ByRef arg As Integer)
arg = 42
End Sub
Public Sub Run()
Test(Prop) '' No problem
End Sub
End Class
El compilador VB.NET resuelve esto generando automáticamente este código para el método Run, expresado en C #:
int temp = Prop;
Test(ref temp);
Prop = temp;
Cuál es la solución alternativa que también puede utilizar. No estoy seguro de por qué el equipo de C # no usó el mismo enfoque. Posiblemente porque no querían ocultar las llamadas getter y setter potencialmente costosas. O el comportamiento completamente no diagnosticable que obtendrá cuando el colocador tenga efectos secundarios que cambien el valor de la propiedad, desaparecerán después de la asignación. Diferencia clásica entre C # y VB.NET, C # es "sin sorpresas", VB.NET es "haz que funcione si puedes".