Propiedades de .NET: ¿Usar un conjunto privado o una propiedad de solo lectura?

40

¿En qué situación debo usar un Conjunto privado en una propiedad en lugar de convertirlo en una propiedad de solo lectura? Tenga en cuenta los dos ejemplos muy simplistas a continuación.

Primer ejemplo:

Public Class Person

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get
        Private Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        Me.Name = txtInfo.ToTitleCase(Me.Name)

    End Sub

End Class

// ----------

public class Person
{
    private string _name;
    public string Name
    {
        get { return _name; }
        private set { _name = value; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(this.Name);
    }
}

Segundo ejemplo:

Public Class AnotherPerson

    Private _name As String

    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        _name = txtInfo.ToTitleCase(_name)

    End Sub

End Class

// ---------------

public class AnotherPerson
{
    private string _name;
    public string Name
    {
        get { return _name; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(_name);
    }
}

Ambos dan los mismos resultados. ¿Es esta una situación en la que no hay lo correcto y lo incorrecto, y es solo una cuestión de preferencia?

    
pregunta tgxiii 29.04.2011 - 18:55

7 respuestas

37

Hay un par de razones para usar private set .

1) Si no está utilizando un campo de respaldo y desea una propiedad automática de solo lectura:

public string Name { get; private set; }   

public void WorkOnName()
{
    TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
    Name = txtInfo.ToTitleCase(Name);
}  

2) Si desea realizar un trabajo adicional cuando modifica la variable dentro de su clase y desea capturarla en una sola ubicación:

private string _name = string.Empty;
public string Name 
{ 
    get { return _name; }
    private set 
    {
        TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(value);
    }
}

En general, sin embargo, es una cuestión de preferencia personal. Por lo que sé, no hay motivos de rendimiento para utilizar uno sobre el otro.

    
respondido por el Adam Lear 29.04.2011 - 19:16
25

Use conjunto privado cuando desee que no se pueda acceder al configurador desde fuera .

Use solo lectura cuando quiera configurar la propiedad solo una vez . En el constructor o inicializador de variable.

PRUEBA ESTO:

void Main()
{
    Configuration config = new Configuration();
    config.ResetConfiguration();

    ConfigurationReadOnly configRO = new ConfigurationReadOnly();
    configRO.ResetConfiguration();
}

public class Configuration
{
    public Color BackgroundColor { get; private set; }
    public Color ForegroundColor { get; private set; }
    public String Text { get; private set; }

    public Configuration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }
}

public class ConfigurationReadOnly
{
    public readonly Color BackgroundColor;
    public readonly Color ForegroundColor;
    public readonly String Text;

    public ConfigurationReadOnly()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black; // compile error: due to readonly keyword
        ForegroundColor = Color.White; // compile error: due to readonly keyword
        Text = String.Empty; // compile error: due to readonly keyword
    }
}
    
respondido por el asakura89 05.03.2013 - 17:39
8

¿Puedo sugerir una tercera opción?

public class Person
{
    public string Name { get; protected set; }

    public void SetName(string name)
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(name);
    }
}

Esto hace que la propiedad Nombre sea de solo lectura para todos los códigos externos y proporciona un método Set explícito. Prefiero el Conjunto explícito en lugar de simplemente utilizar el conjunto en la propiedad Nombre porque está cambiando el valor al establecerlo. Normalmente, si establece un valor de propiedad, espera recuperar el mismo valor cuando llame al get más adelante, lo cual no sucedería si hiciera su ToTitleCase en el < em> set .

Sin embargo, como dijiste, no hay una respuesta correcta.

    
respondido por el Dave Wise 29.04.2011 - 19:12
4

No uses el segundo ejemplo. El objetivo principal de usar una propiedad, incluso si no hay nada más allá de la obtención y la configuración del establecedor, es canalizar todo el acceso a través de esa obtención y configuración para que, si alguna vez necesita cambiar el comportamiento en el futuro, todo esté listo. un solo lugar.

Su segundo ejemplo lo abandona en el caso de establecer la propiedad. Si utilizara ese enfoque en una clase grande y compleja, y luego necesitara cambiar el comportamiento de la propiedad, estaría en un lugar de búsqueda y reemplazo, en lugar de hacer el cambio en un lugar: el setter privado.

    
respondido por el Carson63000 30.04.2011 - 00:23
3

A partir de C # 6.0, las propiedades automáticas de getter-only se han agregado al idioma. Consulte aquí: enlace .

Aquí hay un ejemplo:

public class SomeClass
{
    public int GetOnlyInt { get; }

    public int GetOnlyIntWithInitializer { get; } = 25;

    public SomeClass(int getOnlyInt)
    {
        GetOnlyInt = getOnlyInt;
    }
}
    
respondido por el Daniel Neel 06.07.2016 - 23:16
2

Siempre que he necesitado cambiar el nivel de acceso de un configurador, generalmente lo he cambiado a Protegido (solo esta clase y las clases derivadas pueden cambiar el valor) o Amigo (solo los miembros de mi ensamblaje pueden cambiar el valor) ).

Pero usar Privado tiene mucho sentido cuando quieres hacer otras tareas en el setter además de cambiar el valor de respaldo. Como se señaló anteriormente, es un buen diseño no hacer referencia a sus valores de respaldo directamente, sino que solo acceder a ellos a través de sus propiedades. Eso garantiza que los cambios posteriores que realice en una propiedad se apliquen tanto interna como externamente. Y prácticamente no hay penalización de rendimiento al hacer referencia a una propiedad frente a su variable de respaldo.

    
respondido por el Prlaba 08.10.2012 - 15:16
-1
  

Y prácticamente no hay penalización de rendimiento ...

Pero para aclarar, acceder a una propiedad es más lento que acceder a su variable de respaldo. El captador y definidor de una propiedad son métodos que requieren una llamada y una devolución, mientras que la variable de respaldo de una propiedad se accede directamente.

Es por eso que, en los casos en que se puede acceder al captador de una propiedad muchas veces dentro de un bloque de código, el valor de la propiedad a veces se almacena en caché primero (se guarda en una variable local) y en su lugar se usa la variable local. Por supuesto, eso supone que la propiedad no se puede cambiar de forma asíncrona mientras se ejecuta el bloque.

    
respondido por el Prlaba 14.07.2014 - 14:56

Lea otras preguntas en las etiquetas