variable type parameter functions c# reference parameters field

type - ¿Cómo puedo asignar por "referencia" a un campo de clase en c#?



ref string parameter c# (3)

Estoy tratando de entender cómo asignar por "referencia" a un campo de clase en c #.

Tengo el siguiente ejemplo a considerar:

public class X { public X() { string example = "X"; new Y( ref example ); new Z( ref example ); System.Diagnostics.Debug.WriteLine( example ); } } public class Y { public Y( ref string example ) { example += " (Updated By Y)"; } } public class Z { private string _Example; public Z( ref string example ) { this._Example = example; this._Example += " (Updated By Z)"; } } var x = new X();

Cuando se ejecuta el código anterior, la salida es:

X (Actualizado por Y)

Y no:

X (Actualizado por Y) (Actualizado por Z)

Como esperaba.

Parece que la asignación de un "parámetro de referencia" a un campo pierde la referencia.

¿Hay alguna forma de mantener la referencia cuando se asigna a un campo?

Gracias.


Como otros han notado, no puede tener un campo de tipo "ref a variable". Sin embargo, el solo hecho de saber que no puedes hacerlo es probablemente insatisfactorio; probablemente también quiera saber primero, por qué no, y segundo, cómo evitar esta restricción.

La razón es porque solo hay tres posibilidades:

1) No permitir campos de tipo ref

2) Permitir campos inseguros de tipo ref

3) No use el grupo de almacenamiento temporal para las variables locales (también conocido como "la pila")

Supongamos que permitimos campos de tipo ref. Entonces podrías hacer

public ref int x; void M() { int y = 123; this.x = ref y; }

y ahora se puede acceder a y después de que M complete. Esto significa que o bien estamos en caso (2): el acceso a this.x se bloqueará y morirá horriblemente porque el almacenamiento de y ya no existe, o estamos en caso (3), y el y local está almacenado en el montón recogido de basura, no el grupo de memoria temporal.

Nos gusta la optimización de que las variables locales se almacenen en el grupo temporal, incluso si son aprobadas por ref, y odiamos la idea de que pueda dejar una bomba de tiempo que podría hacer que su programa se bloquee y muera más tarde. Por lo tanto, la opción uno es: sin campos de ref.

Tenga en cuenta que para las variables locales que son variables cerradas de funciones anónimas elegimos la opción (3); esas variables locales no están asignadas fuera del grupo temporal.

Lo cual nos lleva a la segunda pregunta: ¿cómo te las arreglas? Si la razón por la que desea un campo de referencia es hacer un getter y setter de otra variable, eso es perfectamente legal:

sealed class Ref<T> { private readonly Func<T> getter; private readonly Action<T> setter; public Ref(Func<T> getter, Action<T> setter) { this.getter = getter; this.setter = setter; } public T Value { get { return getter(); } set { setter(value); } } } ... Ref<int> x; void M() { int y = 123; x = new Ref<int>(()=>y, z=>{y=z;}); x.Value = 456; Console.WriteLine(y); // 456 -- setting x.Value changes y. }

Y ahí tienes. y se almacena en el montón de gc, x es un objeto que tiene la capacidad de obtener y establecer y .

Tenga en cuenta que el CLR admite los ref locales y los métodos de devolución de ref, aunque C # no. Quizás una versión futura hipotética de C # respalde estas características; Lo prototipé y funciona bien. Sin embargo, esto no es muy importante en la lista de prioridades, así que no me gustaría tener mis esperanzas.

ACTUALIZACIÓN: La característica mencionada en el párrafo anterior finalmente se implementó de manera real en C # 7. Sin embargo, aún no puede almacenar una referencia en un campo.


No. ref es puramente una convención de llamadas. No puedes usarlo para calificar un campo. En Z, _Example se establece en el valor de la referencia de cadena pasada. A continuación, asigne una nueva referencia de cadena utilizando + =. Nunca se asigna al ejemplo, por lo que la referencia no tiene efecto.

La única solución para lo que desea es tener un objeto envoltorio mutable compartido (una matriz o un StringWrapper hipotético) que contenga la referencia (una cadena aquí). Generalmente, si lo necesita, puede encontrar un objeto mutable más grande para que las clases lo compartan.

public class StringWrapper { public string s; public StringWrapper(string s) { this.s = s; } public string ToString() { return s; } } public class X { public X() { StringWrapper example = new StringWrapper("X"); new Z(example) System.Diagnostics.Debug.WriteLine( example ); } } public class Z { private StringWrapper _Example; public Z( StringWrapper example ) { this._Example = example; this._Example.s += " (Updated By Z)"; } }


Olvidaste actualizar la referencia en la clase Z:

public class Z { private string _Example; public Z(ref string example) { example = this._Example += " (Updated By Z)"; } }

Salida: X (Actualizado por Y) (Actualizado por Z)

El punto a tener en cuenta es que el operador + = para una cadena llama al método String.Concat (). Lo cual crea un nuevo objeto de cadena, no actualiza el valor de una cadena. Los objetos de cadena son inmutables, la clase de cadena no tiene ningún método o campo que le permita cambiar el valor. Muy diferente del comportamiento predeterminado de un tipo de referencia regular.

Entonces, si usa un método de cadena u operador, siempre debe asignar el valor de retorno a una variable. Esta es una sintaxis bastante natural, los tipos de valores se comportan de la misma manera. Su código sería muy similar si utilizó una int en lugar de una cadena.