Różnica w języku C # między różnymi stylami pobierania

154

Czasami widzę skróty we właściwościach gettera. Np. Te dwa typy:

public int Number { get; } = 0

public int Number => 0;

Czy ktoś może mi powiedzieć, czy są jakieś różnice między tymi dwoma. Jak się zachowują? Czy oba są tylko do odczytu?

WoIIe
źródło

Odpowiedzi:

266

Tak, oba są tylko do odczytu, ale istnieje różnica. W pierwszym jest pole zapasowe, które jest inicjowane na 0 przed wykonaniem konstruktora. Możesz zmienić wartość tylko w konstruktorze , tak jak zwykłe pole tylko do odczytu. Sam getter po prostu zwraca wartość pola.

W drugim getter po prostu zwraca 0 za każdym razem, bez żadnego pola.

Aby w ogóle uniknąć używania jakichkolwiek automatycznie implementowanych właściwości lub elementów składowych zawierających wyrażenie, mamy:

Pierwsza wersja

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

Druga wersja

public int Number { get { return 0; } }

Wyraźniejszy przykład tej różnicy można zobaczyć w następujący sposób:

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

Jeśli utworzysz pojedynczy obiekt, jego CreationTimewłaściwość zawsze da ten sam wynik - ponieważ jest przechowywana w polu tylko do odczytu, zainicjowana podczas konstrukcji obiektu. Jednak za każdym razem, gdy uzyskasz dostęp do CurrentTimewłaściwości, zostanie DateTime.UtcNowona oceniona, więc otrzymasz potencjalnie inny wynik.

Jon Skeet
źródło
23
Zwróć uwagę, że druga wersja nie zawsze zwraca tę samą wartość. Dobrym przykładem jest powrót random.NextInt(). Pierwsza wersja oceni to raz i zawsze będzie miała tę samą wartość. Drugi za każdym razem zwróci nową wartość.
248

Jedna różnica polega na tym, że 0jest to oceniane: podczas tworzenia obiektu lub gdy właściwość jest używana.

Możesz to lepiej zobaczyć dzięki właściwościom DateTime:

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

    public DateTime Now => DateTime.Now;
}

StartNieruchomość utrzymuje wracając tym samym czasie (na przykład, gdy został stworzony), natomiast Nowzmiany w celu odzwierciedlenia bieżącego czasu.

Wyjaśnienie :

Pierwsza wersja („Start”) dostarcza wartość początkową, która może nawet zostać nadpisana przez konstruktora. Więc to jest oceniane tylko raz.
Druga wersja („Now”) zawiera wyrażenie, które będzie „pobierającym” dla tej właściwości. Więc jest to oceniane za każdym razem, gdy właściwość jest odczytywana. Nie ma nawet pola zapasowego, które konstruktor mógłby nadpisać.

Hans Ke ing
źródło
26
To chyba najważniejsze rozróżnienie.
Matthew,
14
Przyjęta odpowiedź najdokładniej określa różnicę w przykładowym kodzie, ale to wyjaśnia bardziej użyteczną różnicę w obu strukturach.
Kamil Drakari,
3
Wow, dostałeś więcej pozytywnych głosów niż sam słynny Jon Skeet.
machine_1
21

To są funkcje języka C # 6.

Pierwszy przykład

public int Number { get; } = 0

Pierwszym przykładem jest właściwość automatyczna tylko do pobierania . Pole zapasowe właściwości automatycznej tylko do pobierania jest niejawnie deklarowane jako tylko do odczytu.

Drugi przykład

public int Number => 0;

Drugim przykładem są ciała wyrażeń na elementach składowych funkcji podobnych do właściwości . Zauważ, że nie ma żadnego getsłowa kluczowego: jest to sugerowane przez użycie składni ciała wyrażenia.

Oba są tylko do odczytu.

Jehof
źródło
5
... ale jak wyjaśnia Jon Skeet, możesz zmienić wartość zwracaną przez pierwszą.
Martin Bonner wspiera Monikę
2
@MartinBonner ... ale tylko w konstruktorze.
Dennis Kuypers
5
lub, jak zawsze, przez refleksję (drobne czepianie się)
Marco Mp