example - remarks c#
Entendiendo a los instaladores privados (11)
No entiendo la necesidad de tener instaladores privados que comenzaron con C # 2.
Ejemplo de caso de uso:
Tengo una instancia de un objeto de aplicación ''UserInfo''
que contiene una propiedad SessionTokenIDV1
que no deseo exponer a los consumidores de mi clase.
También necesito la capacidad de establecer ese valor de mi clase.
Mi solución fue encapsular la propiedad como se muestra y hacer que el setter sea privado para que pueda establecer el valor del token de sesión sin permitir que el código de instancia también lo configure (o incluso lo vea en mi caso)
public class UserInfo
{
public String SessionTokenIDV1 { get; set; }
}
public class Example
{
// Private vars
private UserInfo _userInfo = new UserInfo();
public string SessionValidV1
{
get { return ((_userInfo.SessionTokenIDV1 != null) && (_userInfo.SessionTokenIDV1.Length > 0)) ? "set" : "unset"; }
private set { _userInfo.SessionTokenIDV1 = value; }
}
}
Editar: edición de etiqueta de código fijo: el ejemplo tenía errores que se corrigieron
No entiendo la necesidad de tener instaladores privados que comenzaron con C # 2.
Tener un método setter para mí es dejar que el usuario establezca algunas variables en esa clase. Al hacerlo, no expondremos las variables directamente a los usuarios. En cambio, les permitimos hacerlo a través de este método de establecimiento público.
Esto para mí es usar "encapsulación". Hay algunos argumentos que afirman que los instaladores privados le permitirán aplicar la encapsulación.
¿No estoy usando la encapsulación usando métodos públicos setter? ¿Por qué necesitamos setters privados?
¿Cuál es la diferencia entre una clase inmutable y una clase con instaladores privados?
No entiendo la necesidad de tener instaladores privados que comenzaron con C # 2.
Por ejemplo, la clase de factura permite al usuario agregar o eliminar elementos de la propiedad Artículos pero no permite al usuario cambiar la referencia de Elementos (es decir, el usuario no puede asignar la propiedad Elementos a otra instancia de objeto de lista de elementos).
public class Item
{
public string item_code;
public int qty;
public Item(string i, int q)
{
this.item_code = i;
this.qty = q;
}
}
public class Invoice
{
public List Items { get; private set; }
public Invoice()
{
this.Items = new List();
}
}
public class TestInvoice
{
public void Test()
{
Invoice inv = new Invoice();
inv.Items.Add(new Item("apple", 10));
List my_items = new List();
my_items.Add(new Item("apple", 10));
inv.Items = my_items; // compilation error here.
}
}
Con la introducción de C # 6.0 y la sintaxis para los Inicializadores de Auto-Propiedad , los setters privados ya no son necesarios para las propiedades que solo se configuran durante la inicialización, ya sea en línea o dentro del constructor.
Estas nuevas sintaxis ahora se compilan:
Propiedad inicializada en línea
public class MyClass1 {
public string MyProperty { get; } = "Aloha!"
}
Propiedad inicializada de constructor
public class MyClass2 {
public string MyProperty { get; }
public MyClass2(string myProperty) {
MyProperty = myProperty;
}
}
Creo que algunas personas han bailado al respecto, pero para mí, el valor de los instaladores privados es que puedes encapsular el comportamiento de una propiedad, incluso dentro de una clase. Como señaló abhishek, si desea despedir un evento de propiedad cambiada cada vez que cambia una propiedad, pero no desea que una propiedad sea leída / escrita al público, entonces debe usar un formador privado, o debe elevar el evento en cualquier lugar que modifique el campo de respaldo. Este último es propenso a errores porque puede olvidar. Relacionado, si la actualización de un valor de propiedad da como resultado que se realice algún cálculo o que se modifique otro campo, o una inicialización lenta de algo, entonces también querrá envolverlo en el formador privado en lugar de tener que recordar hacerlo en cualquier lugar que haga. uso del campo de respaldo.
Digamos, por ejemplo, que no almacena la variable real a través de la propiedad o usa el valor para calcular algo.
En tal caso, puede crear un método para hacer su cálculo
private void Calculate(int value)
{
//...
}
O puedes hacerlo usando
public int MyProperty {get; private set;}
En esos casos, recomendaría usar el más tarde, ya que las propiedades refactorizan cada elemento miembro intacto.
Aparte de eso, si incluso digas que mapea la propiedad con una Variable. En tal caso, dentro de su código desea escribir de esta manera:
public int myprop;
public int MyProperty {get { return myprop;}}
... ...
this.myprop = 30;
... ...
if(this.MyProperty > 5)
this.myprop = 40;
El código anterior luce horrible, ya que el programador siempre debe tener cuidado de usar MyProperty para Get y myprop para Set.
Para mayor coherencia, puede usar un setter privado que hace que Propoerty se lea solo afuera mientras que puede usar su setter dentro de su código.
Es bastante simple. Los setters privados te permiten crear propiedades públicas o protegidas de solo lectura.
Eso es. Esa es la única razón.
Sí, puede crear una propiedad de solo lectura especificando el getter, pero con las propiedades implícitamente automáticas, debe especificar get y set, por lo que si desea que una propiedad implementada automáticamente sea de solo lectura, debe usar establecedores privados. No hay otra forma de hacerlo.
Es cierto que los establecedores privados no se crearon específicamente para las propiedades de solo lectura implementadas automáticamente, pero su uso es un poco más esotérico por otras razones, centrándose principalmente en las propiedades de solo lectura y el uso de la reflexión y la serialización.
Lógicamente.
La presencia de un setter privado se debe a que puede usar propiedad automática:
public int MyProperty { get; set; }
¿Qué harías si quisieras que sea de solo lectura?
public int MyProperty { get; }
¡¡Oh mierda!! No puedo acceder desde mi propia clase; Debería crearlo como una propiedad normal:
private int myProperty;
public int MyProperty { get { return myProperty; } }
Hmm ... pero perdí la función "Propiedad de auto" ...
public int MyProperty { get; private set; }
AHHH ... ¡eso es mejor!
La encapsulación significa que el estado de un objeto solo ocurre a través de una interfaz definida y, debido a esto, la clase puede asegurarse de que este estado sea siempre válido y acorde con el propósito de la clase.
En algunos casos, por lo tanto, está perfectamente de acuerdo con el principio de encapsulación para exponer públicamente un campo: todos los valores posibles para el campo son válidos con todos los demás valores posibles de todos los demás campos y, por lo tanto, el programador puede decidir activamente permitir el campo ser manipulado libremente por código externo.
En general, estos casos están restringidos a clases que en su mayoría son "datos antiguos simples". Tampoco son muy interesantes en este sentido, por lo tanto, basta de ellos.
En otros casos, en otros idiomas, uno tendría un método getter y setter, algo así como int getId()
para obtener un valor y void setId(int val)
para actualizarlo.
Las propiedades nos permiten usar la misma sintaxis para leer y escribir a través de los métodos que usaríamos para leer y escribir un campo. Este es un buen azúcar sintáctico, aunque no vital.
(En realidad, debido a la forma en que funciona la reflexión y casos como DataBinder.Eval
puede ser útil tener una propiedad incluso cuando un campo funcionaría bien, pero eso es otro asunto).
Hasta que se introdujeron los setters privados (en realidad, lo que cambió con C # 2 es la sintaxis para tener un setter privado y un getter público o protegido en el mismo bloque), podríamos tener un método privado para hacer el trabajo del setter privado, entonces los setters privados no son realmente necesarios. Sin embargo, son prácticos, así que, aunque solo sean azúcar sintáctica, son bastante útiles.
La encapsulación no depende de si sus setters (o getters) son públicos, privados, protegidos o internos, sino una cuestión de si son apropiados . Comience con un valor predeterminado de cada campo como privado (y para el caso, readonly
) y luego según sea necesario, agregue miembros (ya sean propiedades o métodos) que modifiquen esos campos, y asegúrese de que el objeto siga siendo válido a medida que cambian . Esto asegura que se mantenga un invariante de clase, lo que significa que las reglas que describen el conjunto válido de estados en el que puede estar nunca se rompen (los constructores también ayudan asegurándose de que comience en tal estado válido).
En cuanto a su última pregunta, ser inmutable significa que una clase no tiene entidades públicas, protegidas o internas y ningún método público, protegido o interno que modifique ningún campo. Hay grados de esto, en C # hay tres grados posibles:
Todos los campos de instancia de una clase son de
readonly
, por lo tanto, incluso el código privado no puede alterarlo. Se garantiza que es inmutable (cualquier cosa que intente cambiarlo no compilará) y posiblemente se puedan hacer optimizaciones detrás de esto.Una clase es inmutable desde el exterior porque ningún miembro público cambia nada, pero no se garantiza mediante el uso de
readonly
para no ser modificado desde el interior.Una clase es inmutable como se ve desde el exterior, aunque algún estado es cambio como un detalle de implementación. Por ejemplo, un campo puede ser memorable, y por lo tanto, desde el exterior, un intento de obtenerlo solo recupera el mismo valor, el primer intento de ese tipo en realidad lo calcula y luego lo almacena para su posterior recuperación.
Necesita un solucionador privado, si desea respaldar el siguiente escenario (no solo para esto, sino que debe señalar una buena razón): Tiene una Propiedad que es de solo lectura en su clase, es decir, solo la clase en sí puede cambiar pero puede cambiarlo después de construir la instancia. Para las vinculaciones, deberás activar un evento PropertyChanged, preferiblemente esto debería hacerse en el establecimiento de propiedades (privado). En realidad, puedes disparar el evento PropertyChanged desde otro lugar en la clase, pero usar el setter privado para esto es "buena ciudadanía", porque no distribuyes tus disparadores de cambio de propiedad en toda tu clase, sino que lo mantienes en el propiedad, donde pertenece.
Sí, está utilizando la encapsulación mediante el uso de propiedades, pero hay más matices para la encapsulación que simplemente tomar el control sobre cómo se leen y escriben las propiedades. Negar una propiedad que se establecerá fuera de la clase puede ser útil tanto para la solidez como para el rendimiento.
Una clase inmutable es una clase que no cambia una vez que se ha creado, por lo que se necesitan entidades privadas (o ningún setter) para proteger las propiedades.
Los setters privados entraron en uso más frecuente con la taquigrafía de la propiedad que se introdujo en C # 3. En C # 2, se omite a menudo al colocador y se accede directamente a los datos privados cuando se establece.
Esta propiedad:
public int Size { get; private set; }
es lo mismo que:
private int _size;
public int Size {
get { return _size; }
private set { _size = value; }
}
excepto que el nombre de la variable de respaldo es creado internamente por el compilador, por lo que no puede acceder a él directamente.
Con la propiedad de taquigrafía, se necesita el solucionador privado para crear una propiedad de solo lectura, ya que no puede acceder directamente a la variable de respaldo.
Un organismo privado es útil si tiene una propiedad de solo lectura y no desea declarar explícitamente la variable de respaldo.
Asi que:
public int MyProperty
{
get; private set;
}
es lo mismo que:
private int myProperty;
public int MyProperty
{
get { return myProperty; }
}
Para las propiedades no implementadas automáticamente, le proporciona una forma consistente de configurar la propiedad desde dentro de su clase, de modo que si necesita validación, etc., solo tiene un lugar.
Para responder a su pregunta final, MSDN tiene esto que decir sobre instaladores privados:
Sin embargo, para clases pequeñas o estructuras que solo encapsulan un conjunto de valores (datos) y tienen poco o ningún comportamiento, se recomienda hacer que los objetos sean inmutables declarando el acceso del conjunto como privado.
Desde la página de MSDN en propiedades implementadas automáticamente