it-swarm.dev

.NET-Eigenschaften - Private Set- oder ReadOnly-Eigenschaft verwenden?

In welcher Situation sollte ich ein privates Set für eine Eigenschaft verwenden, anstatt es zu einer ReadOnly-Eigenschaft zu machen? Berücksichtigen Sie die beiden folgenden sehr vereinfachenden Beispiele.

Erstes Beispiel:

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

Zweites Beispiel:

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

Sie liefern beide die gleichen Ergebnisse. Ist dies eine Situation, in der es kein Richtig und Falsch gibt und es nur eine Frage der Präferenz ist?

48
tgxiii

Es gibt einige Gründe, private set Zu verwenden.

1) Wenn Sie überhaupt kein Hintergrundfeld verwenden und eine schreibgeschützte automatische Eigenschaft wünschen:

public string Name { get; private set; }   

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

2) Wenn Sie zusätzliche Arbeit leisten möchten, wenn Sie die Variable in Ihrer Klasse ändern und diese an einem einzigen Ort erfassen möchten:

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

Im Allgemeinen ist es jedoch eine Frage der persönlichen Präferenz. Soweit ich weiß, gibt es keine Leistungsgründe, um eine über die andere zu verwenden.

43
Adam Lear

Verwenden Sie privates Set, wenn Sie möchten Setter kann nicht von außen aufgerufen werden.

Verwenden Sie schreibgeschützt, wenn Sie die Eigenschaft nur einmal festlegen möchten. Im Konstruktor oder Variableninitialisierer.

TESTEN SIE DIESES :

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
    }
}
31
asakura89

Darf ich eine dritte Option vorschlagen?

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

Dadurch wird die Name-Eigenschaft für alle externen Codes effektiv schreibgeschützt und es wird eine explizite Set-Methode bereitgestellt. Ich bevorzuge das explizite Set, anstatt einfach das set für die Name-Eigenschaft zu verwenden, da Sie den Wert beim Festlegen ändern. Wenn Sie set einen Eigenschaftswert haben, erwarten Sie normalerweise, dass Sie denselben Wert zurückerhalten, wenn Sie später get aufrufen. Dies würde nicht passieren, wenn Sie Ihren ToTitleCase in - ausführen. set.

Wie Sie sagten, gibt es jedoch keine richtige Antwort.

9
Dave Wise

Ab C # 6.0 wurden der Sprache nur Getter-Auto-Eigenschaften hinzugefügt. Siehe hier: https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#getter-only-auto-properties .

Hier ist ein Beispiel:

public class SomeClass
{
    public int GetOnlyInt { get; }

    public int GetOnlyIntWithInitializer { get; } = 25;

    public SomeClass(int getOnlyInt)
    {
        GetOnlyInt = getOnlyInt;
    }
}
5
Daniel Neel

Verwenden Sie nicht das zweite Beispiel. Der springende Punkt bei der Verwendung einer Eigenschaft - selbst wenn nichts anderes als das Erhalten des Getters und die Setter-Einstellung vor sich geht - besteht darin, den gesamten Zugriff über diesen Getter und Setter zu leiten, sodass alles in Ordnung ist, wenn Sie in Zukunft das Verhalten ändern müssen ein Platz.

In Ihrem zweiten Beispiel wird dies beim Festlegen der Eigenschaft aufgegeben. Wenn Sie diesen Ansatz in einer großen, komplexen Klasse verwendet haben und später das Verhalten der Immobilie ändern müssen, befinden Sie sich in Land, in dem Sie suchen und ersetzen, anstatt die Änderung an einem Ort vorzunehmen - dem privaten Setter.

4
Carson63000

Wann immer ich die Zugriffsebene eines Setters ändern musste, habe ich sie im Allgemeinen entweder in "Geschützt" (nur diese Klasse und abgeleitete Klassen können den Wert ändern) oder "Freund" (nur Mitglieder meiner Assembly können den Wert ändern) geändert.

Die Verwendung von Private ist jedoch absolut sinnvoll, wenn Sie neben dem Ändern des Hintergrundwerts auch andere Aufgaben im Setter ausführen möchten. Wie bereits erwähnt, ist es ein gutes Design, nicht direkt auf Ihre Hintergrundwerte zu verweisen, sondern nur über deren Eigenschaften darauf zuzugreifen. Dadurch wird sichergestellt, dass spätere Änderungen, die Sie an einer Eigenschaft vornehmen, sowohl intern als auch extern angewendet werden. Und es gibt praktisch keine Leistungseinbußen bei der Referenzierung einer Eigenschaft gegenüber ihrer Hintergrundvariablen.

2
Prlaba

Und es gibt praktisch keine Leistungseinbußen ...

Um dies zu verdeutlichen, ist der Zugriff auf eine Eigenschaft is langsamer als der Zugriff auf ihre Hintergrundvariable. Der Getter und Setter einer Eigenschaft sind Methoden, die einen Aufruf und eine Rückgabe erfordern, während auf die Sicherungsvariable einer Eigenschaft direkt zugegriffen wird.

Aus diesem Grund wird in Fällen, in denen innerhalb eines Codeblocks häufig auf den Getter einer Eigenschaft zugegriffen werden kann, der Wert der Eigenschaft manchmal zuerst zwischengespeichert (in einer lokalen Variablen gespeichert) und stattdessen die lokale Variable verwendet. Dies setzt natürlich voraus, dass die Eigenschaft nicht asynchron geändert werden kann, während der Block ausgeführt wird.

0
Prlaba