parameter method functions c# arguments pass-by-reference

c# - method - ¿Es posible pasar propiedades como parámetros de "salida" o "ref"?



c# variables by reference (4)

En cambio, deberías hacer algo como esto

WhatEverTheType name; Test(out name); // Choose one of the following construction Person p = new Person(); p.Name = name; Person p = new Person(name); Person p = new Person(Name => name);

¿Puedo pasar una propiedad como un parámetro de "salida" o "ref"? Si no, ¿por qué no?

p.ej

Person p = new Person();

. . .

public void Test(out p.Name);


Otros han explicado que no se puede hacer esto en C #. En VB.NET, puede hacer esto, incluso con la opción estricta / explícita en:

Option Strict On Option Explicit On Imports System.Text Module Test Sub Main() Dim sb as new StringBuilder Foo (sb.Length) End Sub Sub Foo(ByRef x as Integer) End Sub End Module

El código anterior es equivalente a este código C #:

using System.Text; class Test { static void Main() { StringBuilder sb = new StringBuilder(); int tmp = sb.Length; Foo(ref tmp); sb.Length = tmp; } static void Foo(ref int x) { } }

Personalmente, me alegra que C # no tenga esto: está enturbiando mucho las aguas, particularmente en términos del valor de la propiedad si el parámetro se establece dentro del método, pero luego se lanza una excepción.

EDITAR: Según lo solicitado, mi razonamiento sobre por qué creo que pasar propiedades en los fangos de las aguas. Si pasa una variable normal por referencia, entonces esa variable se evalúa cada vez que se hace referencia dentro del método. Si el valor cambia por alguna razón (por ejemplo, como un efecto secundario de algún otro trabajo en el método), ese cambio será inmediatamente visible en el método. Ese no es el caso si pasas una propiedad por referencia en VB.NET: el getter de la propiedad se invoca una vez, y luego se invoca el setter de la propiedad una vez. No es como si estuvieras pasando "aquí hay una propiedad : obtén y configúrala cada vez que uses el parámetro".

Aquí hay un ejemplo completo donde pasar un campo y pasar una propiedad totalmente trivial en .NET tiene resultados muy diferentes:

Option Strict On Option Explicit On Imports System.Text Class Test Dim counter as Integer Property CounterProperty As Integer Get Return counter End Get Set (ByVal value as Integer) counter = value End Set End Property Sub Increment counter += 1 End Sub Shared Sub Main() Dim t as new Test() Console.WriteLine("Counter = {0}", t.counter) t.Foo(t.counter) Console.WriteLine("Counter = {0}", t.counter) t.CounterProperty = 0 Console.WriteLine("CounterProperty = {0}", t.CounterProperty) t.Foo(t.CounterProperty) Console.WriteLine("CounterProperty = {0}", t.CounterProperty) End Sub Sub Foo(ByRef x as Integer) x = 5 Increment Increment Increment x += 1 End Sub End Class


Otra razón por la que esto no está permitido es porque el parámetro ref y out es legible y escribible dentro de un método, mientras que una propiedad puede ser de solo lectura / escritura.

Person { public string Name { get { return "me"; } } }

¿Y ahora si puedes hacer esto?

Test(out p.Name); public void Test(out string name) { name = "someone else"; }

Ahora no eres tú, sino otra persona, pero eso va en contra del contrato que hiciste con get solo el Name propiedad (si alguna vez funcionó). Este es el mismo caso con los campos de solo lectura de la clase, no puedes pasar su referencia.

Person { public readonly string name = "me"; } Test(out p.name); //not possible.

Puede ser C# puede venir con un argumento readonly / writeonly para un método:

public void Test(out settable string name, gettable int count, bool whatever) { name = "someone else"; } Test(out p.Name, 0, true); // doesnt compile since p.Name is readonly.


Disculpas por la respuesta corta, pero no, la especificación del lenguaje C # no lo permite.

Vea esta respuesta a otra pregunta para ver qué sucede cuando lo intenta. También dice por qué no debe hacer que la propiedad sea solo un campo público para evitar la restricción.

Espero que esto ayude

EDIT: preguntas por qué?

Si pasa una variable a un parámetro de out o ref , en realidad está pasando la dirección (o ubicación en la memoria) de la variable. Dentro de la función, el compilador sabe dónde está realmente la variable y obtiene y escribe valores en esa dirección.

Una propiedad se ve como un valor, pero en realidad es un par de funciones, cada una con una firma diferente. Por lo tanto, para pasar una propiedad, en realidad necesitaría pasar dos punteros a función, uno para obtener y otro para el conjunto.

Eso es algo completamente diferente para pasar a una función que la dirección de una variable

es decir, una dirección variable v dos punteros de función.

Actualizar
¿Por qué C # no se ocupa de esto por nosotros?

No soy Eric Lippert , pero voy a ver por qué

¿Cuál debería ser la firma de la función a la que llamas?
Digamos que quieres llamar a void MyFn(ref int i) si eso sigue así, ¿o debería cambiar para decir que también permitimos propiedades? Si cambia a alguna sintaxis como void MyFn(prop_ref int i) entonces esto es bastante inútil, no puede pasar propiedades a las funciones de la biblioteca o código de terceros que no fue escrito con el modificador especial prop_ref. De todos modos, creo que estás sugiriendo que no debería ser diferente.

Ahora digamos que MyFn i pasa a una función COM, o llamada a WinAPI, pasando la dirección de i (es decir, fuera de .net, por ref). Si es una propiedad, ¿cómo se obtiene la dirección de i ? No puede haber ninguna int real debajo de la propiedad para obtener la dirección de. ¿Haces lo que hace VB.Net?

El compilador Vb.Net detecta cuando una propiedad se pasa como un argumento ByRef a un método. En ese momento, declara una variable, copia la propiedad en la variable, pasa la variable byref y luego, una vez que se llama al método, copia la variable nuevamente en la propiedad. es decir

MyFunc(myObject.IntProperty)

se convierte

Dim temp_i As Integer = myObject.IntProperty MyFunc(temp_i) myObject.IntProperty = temp_i

Cualquier efecto secundario de propiedad no ocurre hasta que MyFunc regrese, lo que puede causar todo tipo de problemas y provocar errores muy sutiles.

En mi humilde opinión, la solución Vb.Net para este problema también está rota, así que no voy a aceptar eso como una respuesta.

¿Cómo crees que el compilador de C # debería manejar esto?