tag - summary example c#
Propiedad C#y parámetro ref, ¿por qué no hay azúcar? (9)
Me encontré con este mensaje de error mientras trabajaba en C #
Una propiedad o indexador no se puede pasar como un parámetro de salida o ref
Sé lo que causó esto e hice la solución rápida de crear una variable local del tipo correcto, llamando a la función con él como el parámetro out
/ ref
y luego asignándolo de nuevo a la propiedad:
RefFn(ref obj.prop);
se convierte en
{
var t = obj.prop;
RefFn(ref t);
obj.prop = t;
}
Claramente, esto fallaría si la propiedad no admite get y set en el contexto actual.
¿Por qué C no hace eso por mí?
Los únicos casos en los que puedo pensar dónde esto podría causar problemas son:
- enhebrado
- excepciones
Para enhebrar esa transformación, afecta cuando las escrituras suceden (después de la llamada de función vs. en la llamada de función), pero sospecho que cualquier código que cuente con eso tendrá poca simpatía cuando se rompa.
Para excepciones, la preocupación sería; ¿Qué ocurre si la función se asigna a uno de los varios parámetros de ref
que arroja? Cualquier solución trivial daría como resultado que todos o ninguno de los parámetros se asignen cuando algunos deberían estar y otros no. De nuevo, no creo que esto sea compatible con el uso del idioma.
Nota: Entiendo la mecánica de por qué se generan estos mensajes de error. Lo que estoy buscando es la razón por la cual C # no implementa automáticamente la solución trivial.
Cuando pasa ref / out antepuesto significa que está pasando un tipo de referencia que está almacenado en el montón.
Las propiedades son métodos de contenedor, no variables.
Este sitio parece tener un trabajo para usted. No lo he probado, así que no puedo garantizar que funcione. El ejemplo parece usar la reflexión para obtener acceso a las funciones de obtención y establecimiento de la propiedad. Probablemente no sea un enfoque recomendado, pero podría lograr lo que está pidiendo.
La razón de esto es que C # no admite propiedades "parametricas" que aceptan parámetros pasados por referencia. Es interesante observar que el CLR admite esta funcionalidad, pero C # no.
Las propiedades no son más que azúcar sintáctico sobre los métodos getX / setX del estilo Java. No tiene mucho sentido para ''ref'' en un método. En su caso, tendría sentido porque sus propiedades simplemente están borrando campos. Las propiedades no tienen que ser simplemente stubs, por lo tanto, el framework no puede permitir ''ref'' en Propiedades.
EDITAR : Bueno, la respuesta simple es que el mero hecho de que una propiedad getter o setter pueda incluir mucho más que solo un campo de lectura / escritura lo hace indeseable, sin mencionar posiblemente inesperado, para permitir el tipo de azúcar que está proponiendo. Esto no quiere decir que no haya estado necesitando esta funcionalidad antes, solo que entiendo por qué no quieren proporcionarla.
No sería seguro para hilos; si dos subprocesos crean simultáneamente sus propias copias del valor de propiedad y las pasan a funciones como parámetros de ref, solo una de ellas termina en la propiedad.
class Program
{
static int PropertyX { get; set; }
static void Main()
{
PropertyX = 0;
// Sugared from:
// WaitCallback w = (o) => WaitAndIncrement(500, ref PropertyX);
WaitCallback w = (o) => {
int x1 = PropertyX;
WaitAndIncrement(500, ref x1);
PropertyX = x1;
};
// end sugar
ThreadPool.QueueUserWorkItem(w);
// Sugared from:
// WaitAndIncrement(1000, ref PropertyX);
int x2 = PropertyX;
WaitAndIncrement(1000, ref x2);
PropertyX = x2;
// end sugar
Console.WriteLine(PropertyX);
}
static void WaitAndIncrement(int wait, ref int i)
{
Thread.Sleep(wait);
i++;
}
}
PropertyX termina en 1, mientras que un campo o variable local sería 2.
Esa muestra de código también resalta las dificultades introducidas por cosas como métodos anónimos cuando se le pide al compilador que haga cosas azucaradas.
Porque está pasando el resultado del indexador, que es realmente el resultado de una llamada a un método. No hay garantía de que la propiedad del indexador también tenga un setter, y pasarlo por ref generaría una seguridad falsa por parte del desarrollador cuando crea que su propiedad se va a establecer sin que se llame al setter.
En un nivel más técnico, ref y out pasan la dirección de memoria del objeto pasado a ellos, y para establecer una propiedad, debe llamar al setter, por lo que no hay garantía de que la propiedad realmente se cambie, especialmente cuando el tipo de propiedad es inmutable. ref y out no solo establecen el valor al devolver el método, pasan la referencia de memoria real al objeto en sí.
Puede usar campos con ref
/ out
, pero no propiedades. La razón es que las propiedades son solo un atajo de sintaxis para métodos especiales. El compilador realmente traduce las propiedades get / set a los métodos get_X
y set_X
correspondientes ya que el CLR no tiene soporte inmediato para las propiedades.
Si está preguntando por qué el compilador no sustituye el campo devuelto por el getter de la propiedad, es porque el getter puede devolver un const o readonly o literal o algo más que no debe ser reinicializado o sobrescrito.
Solo por información, C # 4.0 tendrá algo así como este azúcar, pero solo cuando llame a métodos de interoperabilidad, en parte debido a la gran propensión de la ref
en este escenario. No lo he probado mucho (en el CTP); tendremos que ver cómo se desarrolla ...