Proprietà .NET - Usa set privato o proprietà ReadOnly?

42

In quale situazione dovrei usare un Set privato su una proprietà piuttosto che renderlo una proprietà ReadOnly? Prendi in considerazione i due esempi molto semplicistici di seguito.

Primo esempio:

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);
    }
}

Secondo esempio:

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);
    }
}

Entrambi producono gli stessi risultati. Si tratta di una situazione in cui non c'è giusto e sbagliato, ed è solo una questione di preferenza?

    
posta tgxiii 29.04.2011 - 18:55
fonte

7 risposte

38

Ci sono un paio di motivi per usare private set .

1) Se non si utilizza affatto un campo di supporto e si desidera una proprietà automatica di sola lettura:

public string Name { get; private set; }   

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

2) Se vuoi fare un lavoro extra quando modifichi la variabile all'interno della tua classe e vuoi catturarla in una singola posizione:

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

In generale, però, è una questione di preferenze personali. Per quel che ne so, non ci sono ragioni per le prestazioni per usarne uno sull'altro.

    
risposta data 29.04.2011 - 19:16
fonte
26

Utilizza set privato quando vuoi che setter non sia accessibile dall'esterno .

Utilizza readonly quando vuoi impostare la proprietà solo una volta . Nel costruttore o nell'inizializzatore di variabili.

PROVA QUESTO:

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
    }
}
    
risposta data 05.03.2013 - 17:39
fonte
8

Potrei suggerire una terza opzione?

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);
    }
}

Questo rende la proprietà Name efficacemente sola lettura a tutto il codice esterno e fornisce un metodo Set esplicito. Preferisco l'insieme esplicito invece di usare semplicemente set nella proprietà Name perché si sta modificando il valore quando lo si imposta. Normalmente, se imposta un valore di proprietà, ci si aspetta di ottenere lo stesso valore quando si chiama get in un secondo momento, cosa che non succederebbe se si fosse fatto il ToTitleCase nel < em> set .

Tuttavia, come hai detto, non esiste una risposta giusta.

    
risposta data 29.04.2011 - 19:12
fonte
4

Non usare il secondo esempio. L'intero punto di utilizzo di una proprietà - anche se non c'è nulla che vada oltre il get getter e l'impostazione setter - è quello di incanalare tutti gli accessi attraverso quel getter and setter in modo che se hai bisogno di cambiare comportamento in futuro, è tutto in un posto.

Il tuo secondo esempio abbandona quello in caso di impostazione della proprietà. Se avessi usato quell'approccio in una classe ampia e complessa, e in seguito avessi avuto bisogno di cambiare il comportamento della proprietà, saresti nella ricerca e sostituisci la terra, invece di fare la modifica in un unico posto: il setter privato.

    
risposta data 30.04.2011 - 00:23
fonte
4

A partire da C # 6.0, sono state aggiunte proprietà automatiche solo getter nella lingua. Vedi qui: link .

Ecco un esempio:

public class SomeClass
{
    public int GetOnlyInt { get; }

    public int GetOnlyIntWithInitializer { get; } = 25;

    public SomeClass(int getOnlyInt)
    {
        GetOnlyInt = getOnlyInt;
    }
}
    
risposta data 06.07.2016 - 23:16
fonte
2

Ogni volta che ho bisogno di cambiare il livello di accesso di un setter, in genere l'ho cambiato su Protetto (solo questa classe e le classi derivate possono modificare il valore) o Friend (solo i membri del mio assembly possono modificare il valore ).

Ma usare Private ha perfettamente senso quando si vogliono svolgere altre attività nel setter oltre a modificare il valore di backing. Come sottolineato in precedenza, è buona norma non fare riferimento direttamente ai valori di backing, ma solo accedervi tramite le loro proprietà. Ciò garantisce che le modifiche successive apportate a una proprietà vengano applicate internamente e esternamente. E non c'è praticamente alcuna penalità di prestazioni per fare riferimento a una proprietà rispetto alla sua variabile di supporto.

    
risposta data 08.10.2012 - 15:16
fonte
-1

And there's virtually no performance penalty...

Ma per chiarire, l'accesso a una proprietà è più lento di accedere alla sua variabile di supporto. Il getter e il setter di una proprietà sono metodi che richiedono una chiamata e un ritorno, mentre è possibile accedere direttamente alla variabile di supporto di una proprietà.

Ecco perché, nei casi in cui un getter di una proprietà può essere consultato più volte all'interno di un blocco di codice, il valore della proprietà viene talvolta memorizzato prima nella cache (salvato in una variabile locale) e la variabile locale viene invece utilizzata. Ovviamente, si presuppone che la proprietà non possa essere modificata in modo asincrono mentre il blocco è in esecuzione.

    
risposta data 14.07.2014 - 14:56
fonte

Leggi altre domande sui tag