Automatisierte Eigenschaft nur mit Getter, kann eingestellt werden, warum?


95

Ich habe eine automatisierte Eigenschaft erstellt:

public int Foo { get; } 

Dies ist nur Getter. Aber wenn ich einen Konstruktor erstelle, kann ich den Wert ändern:

public MyClass(string name)
{
    Foo = 5;
}

Warum ist es möglich, obwohl dies nur get ist?


Es wird eigentlich kein Setter verwendet (weil es keinen hat). Es setzt direkt das zugrunde liegende Feld (das vor uns verborgen ist, weshalb Sie den Eigenschaftsnamen verwenden müssen)
Dennis_E

14
Was nützt eine Eigenschaft, wenn sie niemals initialisiert / festgelegt werden kann? Yacoub Massad hat es perfekt beantwortet
Vikhram

Antworten:


122

Dies ist eine neue C # 6-Funktion, "Getter-only auto-properties", auch bekannt als "Auto-Property Initializers for Read-Only Properties", wie in diesem MSDN-Zeitschriftenartikel "C #: The New and Improved C # 6.0" von Mark beschrieben Michaelis und im C # 6.0-Entwurf der Sprachspezifikation .

Auf den Setter des schreibgeschützten Felds kann nur im Konstruktor zugegriffen werden. In allen anderen Szenarien ist das Feld weiterhin schreibgeschützt und verhält sich wie zuvor.

Dies ist eine praktische Syntax, um die Menge an Code zu reduzieren, die Sie eingeben müssen, und um die Notwendigkeit zu beseitigen, eine Variable auf privater Modulebene explizit zu deklarieren, um den Wert zu speichern.

Diese Funktion wurde als wichtig angesehen, da seit der Einführung der automatisch implementierten Eigenschaften in C # 3 veränderbare Eigenschaften (mit Getter und Setter) schneller zu schreiben waren als unveränderliche (mit nur Getter), was bedeutet, dass dies Personen waren Sie sind versucht, veränderbare Eigenschaften zu verwenden, um zu vermeiden, dass Sie den Code für ein Hintergrundfeld eingeben müssen, das normalerweise für schreibgeschützte Eigenschaften erforderlich ist. Weitere Informationen zu automatisch implementierten Eigenschaften finden Sie im entsprechenden Abschnitt des Microsoft C # -Programmierhandbuchs .

Dieser Blog-Beitrag '# 1,207 - C # 6.0 - Auto-Property-Initialisierer für schreibgeschützte Eigenschaften' von Sean Sexton enthält eine gute Erklärung und ein Beispiel wie folgt:

Wenn Sie vor C # 6.0 eine schreibgeschützte (unveränderliche) Eigenschaft wünschen, verwenden Sie normalerweise ein schreibgeschütztes Sicherungsfeld, das im Konstruktor initialisiert wird, wie unten gezeigt.

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

In C # 6.0 können Sie automatisch implementierte Eigenschaften verwenden, um eine schreibgeschützte Eigenschaft zu implementieren. Verwenden Sie dazu einen Auto-Property-Initialisierer. Das Ergebnis ist viel sauberer als im obigen Beispiel, in dem wir explizit ein Hintergrundfeld deklarieren mussten.

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

Weitere Details finden Sie auch im Dotnet Roslyn Repo auf GitHub :

Auto-Eigenschaften können jetzt ohne Setter deklariert werden.

Das Hintergrundfeld einer Nur-Getter-Auto-Eigenschaft wird implizit als schreibgeschützt deklariert (obwohl dies nur für Reflexionszwecke von Bedeutung ist). Sie kann wie im obigen Beispiel über einen Initialisierer für die Eigenschaft initialisiert werden. Außerdem kann im Konstruktorkörper des deklarierenden Typs eine Nur-Getter-Eigenschaft zugewiesen werden, wodurch der Wert direkt dem zugrunde liegenden Feld zugewiesen wird:

Hier geht es darum, Typen präziser auszudrücken, aber beachten Sie, dass dadurch auch ein wichtiger Unterschied in der Sprache zwischen veränderlichen und unveränderlichen Typen beseitigt wird: Auto-Eigenschaften waren nur dann eine Abkürzung, wenn Sie bereit waren, Ihre Klasse veränderbar zu machen, und damit die Versuchung, Standardwerte zu verwenden das war toll. Mit den Nur-Getter-Auto-Eigenschaften wurde das Spielfeld zwischen veränderlich und unveränderlich ausgeglichen.

und im Entwurf der Sprachspezifikation C # 6.0 (Hinweis: Die Sprachspezifikation ist für Microsoft endgültig, muss jedoch noch als EMCA / ISO-Standard genehmigt werden , daher der „Entwurf“):

Automatisch implementierte Eigenschaften

Eine automatisch implementierte Eigenschaft (oder kurz Auto-Eigenschaft) ist eine nicht abstrakte nicht externe Eigenschaft mit Nur-Semikolon-Zugriffskörpern. Auto-Eigenschaften müssen einen Get-Accessor haben und können optional einen festgelegten Accessor haben.

Wenn eine Eigenschaft als automatisch implementierte Eigenschaft angegeben wird, ist automatisch ein verstecktes Sicherungsfeld für die Eigenschaft verfügbar, und die Accessoren werden implementiert, um aus diesem Sicherungsfeld zu lesen und in dieses zu schreiben. Wenn für die Auto-Eigenschaft kein Accessor festgelegt ist, wird das Hintergrundfeld als schreibgeschützt (schreibgeschützte Felder) betrachtet. Genau wie ein schreibgeschütztes Feld kann auch im Body eines Konstruktors der einschließenden Klasse eine Nur-Getter-Auto-Eigenschaft zugewiesen werden. Eine solche Zuweisung wird direkt dem schreibgeschützten Hintergrundfeld der Eigenschaft zugewiesen.

Eine Auto-Eigenschaft kann optional einen property_initializer haben, der als variable_initializer (Variable initializers) direkt auf das Hintergrundfeld angewendet wird.


1
Das ist dummes Design. Dies sollte ein Fehler bei der Kompilierung sein, wenn er an einem Ort festgelegt wird, an dem die Eigenschaft als schreibgeschützt betrachtet wird.
Shiv

Das Seltsame für mich ist, dass es immer noch einen Compilerfehler gibt, der besagt, CS0200 C# Property or indexer cannot be assigned to -- it is read onlywenn eine reguläre Eigenschaft verwendet wird. Werden "Nur-Getter-Auto-Eigenschaften" als schreibgeschützt betrachtet oder nicht?
Kyle Delaney

24

Dies ist eine neue Funktion in C # 6 , mit der Sie schreibgeschützte Eigenschaften erstellen und deren Werte vom Konstruktor aus initialisieren können (oder inline, wenn Sie sie deklarieren).

Wenn Sie versuchen, den Wert dieser Eigenschaft außerhalb des Konstruktors zu ändern, wird ein Kompilierungsfehler angezeigt.

Es ist schreibgeschützt in dem Sinne, dass Sie den Wert nach dem Initialisieren des Werts (inline oder innerhalb des Konstruktors) nicht mehr ändern können.


Also, was ist die Erklärung? Was ist die Definition eines Getters?
Noam B.

16

Wenn es nicht möglich wäre, die schreibgeschützte Eigenschaft vom Konstruktor (oder einem Initialisierer für automatische Eigenschaften) zu initialisieren, wäre dies nutzlos, da immer der Standardwert für seinen Typ zurückgegeben würde (0 für Zahlen, null für Referenztypen) ). Dieselbe Semantik galt für schreibgeschützte Felder in allen C # -Versionen.

Um eine echte Getter-Only-Eigenschaft zu definieren (die nicht vom Konstruktor initialisiert werden kann), müssen Sie angeben, was sie als Teil der Definition zurückgibt:

public int Foo { get { return 5; } }

Oder genauer gesagt in C # 6:

public int Foo => 5;

Nicht ganz wahr, schreibgeschützte Eigenschaften sind sehr nützlich, um eine Bedingung in Ihren Code zu kapseln. Sie können eine if-Anweisung und fast jeden Code schreiben, um andere Eigenschaften oder Bedingungen zu bewerten und jedes Mal, wenn Sie die Eigenschaft lesen, einen geeigneten Wert zurückzugeben
sebagomez

3
@sebagomez: Ich bin nicht sicher, ob ich Ihren Standpunkt verstehe - habe ich das nicht in meinem Beispiel gezeigt?
Douglas

5

"Schreibgeschützt automatisch implementierte Eigenschaften"

Zunächst möchte ich klarstellen, dass die Immobilie gefällt

public string FirstName { get; }

Ist bekannt als "schreibgeschützt automatisch implementierte Eigenschaften"

Um dies zu überprüfen, können Sie den obigen Code mit Visual Studio ausführen und überprüfen. Wenn Sie die Sprachversion von C # 6.0 auf C # 5.0 ändern, löst der Compiler die folgende Ausnahme aus. Die Funktion "Nur schreibgeschützte automatisch implementierte Eigenschaften" ist in C # 5 nicht verfügbar. Verwenden Sie die Sprachversion 6 oder höher.

Um die C # -Sprachenversion zu ändern, besuchen Sie hier

Jetzt komme ich zu Ihrer zweiten Frage

„Das ist nur Getter. Aber wenn ich einen Konstruktor baue, kann ich den Wert ändern. “

Microsoft führt die "schreibgeschützt automatisch implementierten Eigenschaften" in die schreibgeschützte Logik ein. Wie wir wissen, ist das Schlüsselwort "readonly" ab C # 1.0 verfügbar. Wir verwenden das Schlüsselwort "readonly" als Modifikator für ein Feld. Dieses Feld kann entweder zum Zeitpunkt der Deklaration oder in einem Konstruktor derselben Klasse auf zwei Arten zugewiesen werden .

Auf die gleiche Weise kann der Wert von "schreibgeschützt automatisch implementierten Eigenschaften" auf zwei Arten zugewiesen werden

Weg1 (zum Zeitpunkt der Erklärung):

public string FirstName { get; } = "Banketeshvar";

Way2 (in einem Konstruktor derselben Klasse)

Person()
{
 FirstName  = "Banketeshvar";
}

Rein ReadOnly-Eigenschaft

Wenn Sie nach einer reinen Readonly-Immobilie suchen, dann entscheiden Sie sich dafür

public string FullName => "Manish Sharma";

Jetzt können Sie dem Konstruktor keinen Wert für die Eigenschaft "FullName" zuweisen. Wenn Sie dies versuchen, werden die folgenden Ausnahmen ausgelöst

"Eigenschaft oder Indexer 'Person.FullName' kann nicht zugewiesen werden - es ist schreibgeschützt"


1
Beachten Sie, dass FullName => "foo bar" JEDES MAL ausgewertet wird.
JuFo

4

Die Funktion für automatische Eigenschaften wurde der Sprache während der Version C # 3.0 hinzugefügt. Sie können eine Eigenschaft ohne Hintergrundfeld definieren. Sie müssen jedoch weiterhin den Konstruktor verwenden, um diese automatischen Eigenschaften auf einen nicht standardmäßigen Wert zu initialisieren. In C # 6.0 wird eine neue Funktion namens Auto Property Initializer eingeführt, mit der Sie diese Eigenschaften ohne einen Konstruktor wie den folgenden initialisieren können:

Bisher ist ein Konstruktor erforderlich, wenn Sie Objekte mit einer Auto-Eigenschaft erstellen und eine Auto-Eigenschaft mit einem nicht standardmäßigen Wert wie folgt initialisieren möchten:

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

In C # 6.0 bedeutet die Möglichkeit, einen Initialisierer mit der Eigenschaft auto zu verwenden, dass kein expliziter Konstruktorcode erforderlich ist.

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

Weitere Informationen hierzu finden Sie hier


1

Eine deklarierte Variable readonlykann innerhalb eines Konstruktors geschrieben werden, aber in Sprachen, die das Attribut berücksichtigen, kann sie nach der Rückkehr des Konstruktors nicht mehr geändert werden. Dieses Qualifikationsmerkmal wurde als Sprachfunktion bereitgestellt, da es häufig für Felder erforderlich ist, deren Werte basierend auf Konstruktorparametern variieren (dh sie können nicht vor dem Start des Konstruktors initialisiert werden), müssen sich jedoch nach der Rückkehr der Konstruktoren nicht ändern, dies war jedoch der Fall Nur für Variablen verwendbar, die als Felder verfügbar gemacht werden. Die Semantik vonreadonly qualifizierter Felder wäre in vielen Fällen für öffentliche Mitglieder perfekt gewesen, außer dass es für Klassen oft besser ist, Mitglieder - auch unveränderliche - als Eigenschaften anstatt als Felder verfügbar zu machen.

So wie es Lese- / Schreib-Autoeigenschaften gibt, mit denen Klassen veränderbare Eigenschaften genauso einfach wie normale Felder readonlyverfügbar machen können, gibt es schreibgeschützte Autoeigenschaften , mit denen Klassen unveränderliche Eigenschaften so einfach wie qualifizierte Felder verfügbar machen können. So wie readonlyqualifizierte Felder in einem Konstruktor geschrieben werden können, so auch mit get-only-Eigenschaften.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.