Unterschied in C # zwischen verschiedenen Getterstilen

154

Ich sehe manchmal Abkürzungen in den Eigenschaften für den Getter. ZB diese beiden Typen:

public int Number { get; } = 0

public int Number => 0;

Kann mir bitte jemand sagen, ob es Unterschiede zwischen diesen beiden gibt. Wie verhalten sie sich? Sind beide schreibgeschützt?

WoIIe
quelle

Antworten:

266

Ja, beide sind schreibgeschützt, aber es gibt einen Unterschied. Im ersten gibt es ein Hintergrundfeld, das vor der Ausführung des Konstruktors auf 0 initialisiert wird. Sie können den Wert nur im Konstruktor ändern , genau wie in einem normalen schreibgeschützten Feld. Der Getter selbst gibt nur den Wert des Feldes zurück.

Im zweiten Fall gibt der Getter jedes Mal nur 0 zurück, ohne dass ein Feld beteiligt ist.

Um zu vermeiden, dass automatisch implementierte Eigenschaften oder ausdrucksstarke Elemente verwendet werden, haben wir:

Erste Version

private readonly int _number = 0;
public int Number { get { return _number; } }

Zweite Version

public int Number { get { return 0; } }

Ein klareres Beispiel für den Unterschied könnte folgendermaßen gesehen werden:

public DateTime CreationTime { get; } = DateTime.UtcNow;
public DateTime CurrentTime => DateTime.UtcNow;

Wenn Sie ein einzelnes Objekt erstellen, CreationTimeliefert seine Eigenschaft immer das gleiche Ergebnis, da es in einem schreibgeschützten Feld gespeichert ist, das bei der Objektkonstruktion initialisiert wurde. Jedes Mal, wenn Sie auf die CurrentTimeEigenschaft zugreifen , wird DateTime.UtcNowdies jedoch ausgewertet, sodass Sie möglicherweise ein anderes Ergebnis erhalten.

Jon Skeet
quelle
23
Beachten Sie, dass die zweite Version nicht immer den gleichen Wert zurückgibt. Ein gutes Beispiel ist, wenn Sie zurückkehren random.NextInt(). Die erste Version wertet das einmal aus und hat immer den gleichen Wert. Der zweite gibt jedes Mal einen neuen Wert zurück.
248

Ein Unterschied besteht darin, wann dies 0ausgewertet wird: bei der Objekterstellung oder wenn die Eigenschaft verwendet wird.

Sie können dies mit den DateTime-Eigenschaften besser sehen:

class SomeTestClass
{
    public DateTime Start { get; } = DateTime.Now;

    public DateTime Now => DateTime.Now;
}

Die StartEigenschaft gibt immer dieselbe Zeit zurück (zum Zeitpunkt der Erstellung der Instanz), während NowÄnderungen vorgenommen werden, um die aktuelle Zeit wiederzugeben.

Erklärung :

Die erste Version ("Start") liefert einen Anfangswert, der möglicherweise sogar vom Konstruktor überschrieben wird. Dies wird also nur einmal ausgewertet.
Die zweite Version ("Jetzt") enthält den Ausdruck, der der "Getter" dieser Eigenschaft sein wird. Dies wird also jedes Mal ausgewertet, wenn die Eigenschaft gelesen wird. Es gibt nicht einmal ein Hintergrundfeld, das der Konstruktor überschreiben kann.

Hans Keing
quelle
26
Dies ist der wichtigste Unterschied, den ich denke.
Matthew
14
Die akzeptierte Antwort definiert den Unterschied im Beispielcode am genauesten, dies erklärt jedoch einen nützlicheren Unterschied zwischen den beiden Strukturen.
Kamil Drakari
3
Wow, du hast mehr Stimmen als der berühmte Jon Skeet selbst.
machine_1
21

Dies sind C # 6-Sprachfunktionen.

Erstes Beispiel

public int Number { get; } = 0

Das erste Beispiel ist eine Nur-Getter-Auto-Eigenschaft . Das Hintergrundfeld einer Nur-Getter-Auto-Eigenschaft wird implizit als schreibgeschützt deklariert.

Zweites Beispiel

public int Number => 0;

Das zweite Beispiel sind Ausdruckskörper auf eigenschaftsähnlichen Funktionselementen . Beachten Sie, dass es kein getSchlüsselwort gibt: Es wird durch die Verwendung der Ausdruckskörpersyntax impliziert.

Beide sind schreibgeschützt.

Jehof
quelle
5
... aber wie Jon Skeet erklärt, können Sie den Wert ändern, den der erste zurückgibt.
Martin Bonner unterstützt Monica
2
@ MartinBonner ... aber nur im Konstruktor.
Dennis Kuypers
5
oder wie immer durch Reflexion (geringfügiges Nitpicking)
Marco Mp