Właściwość automatyczna tylko z funkcją pobierającą, może być ustawiona, dlaczego?

97

Utworzyłem zautomatyzowaną usługę:

public int Foo { get; } 

To jest tylko getter. Ale kiedy buduję konstruktora, mogę zmienić wartość:

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

Dlaczego jest to możliwe, mimo że jest to opcja tylko do zdobycia?

Noam B.
źródło
W rzeczywistości nie używa setera (ponieważ go nie ma). Bezpośrednio ustawia podstawowe pole (które jest przed nami ukryte, dlatego musisz użyć nazwy właściwości)
Dennis_E
14
Po co jest właściwość, jeśli nigdy nie można jej zainicjować / ustawić? Yacoub Massad odpowiedział na to doskonale
Vikhram

Odpowiedzi:

123

To jest nowa funkcja języka C # 6, „właściwości automatyczne tylko do pobierania”, znana również jako „Inicjatory właściwości automatycznych dla właściwości tylko do odczytu”, jak omówiono w tym artykule z magazynu MSDN „C #: The New and Improved C # 6.0” autorstwa Marka Michaelis iw specyfikacji języka C # 6.0 .

Metoda ustawiająca pole tylko do odczytu jest dostępna tylko w konstruktorze, we wszystkich innych scenariuszach pole jest nadal tylko do odczytu i zachowuje się jak poprzednio.

Jest to wygodna składnia, która zmniejsza ilość kodu, który trzeba wpisać, i eliminuje potrzebę jawnego zadeklarowania zmiennej poziomu modułu prywatnego do przechowywania wartości.

Ta funkcja była postrzegana jako ważna, ponieważ od czasu wprowadzenia właściwości implementowanych automatycznie w C # 3, zmienne właściwości (te z funkcją pobierającą i ustawiającą) stały się szybsze w zapisie niż niezmienne (te z tylko funkcją pobierającą), co oznacza, że ​​ludzie byli jest kuszony do używania właściwości modyfikowalnych, aby uniknąć konieczności wpisywania kodu dla pola zapasowego, które zwykle jest wymagane dla właściwości tylko do odczytu. Więcej informacji na temat właściwości implementowanych automatycznie znajduje się w odpowiedniej sekcji przewodnika programowania C # firmy Microsoft .

Ten wpis na blogu „# 1,207 - C # 6.0 - Auto-inicjatory właściwości dla właściwości tylko do odczytu” autorstwa Seana Sextona zawiera dobre wyjaśnienie i przykład w następujący sposób:

Przed C # 6,0, jeśli chcesz mieć właściwość tylko do odczytu (niezmienną), zwykle używałbyś pola zapasowego tylko do odczytu, które jest inicjowane w konstruktorze, jak pokazano poniżej.

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

W C # 6,0 można użyć właściwości zaimplementowanych automatycznie, aby zaimplementować właściwość tylko do odczytu. Robisz to za pomocą inicjatora właściwości automatycznych. Wynik jest znacznie czystszy niż w powyższym przykładzie, w którym musieliśmy jawnie zadeklarować pole zapasowe.

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

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

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

Więcej szczegółów można również znaleźć w repozytorium dotnet Roslyn w serwisie GitHub :

Właściwości automatyczne można teraz deklarować bez metody ustawiającej.

Pole zapasowe właściwości automatycznej tylko do pobierania jest niejawnie zadeklarowane jako tylko do odczytu (choć ma to znaczenie tylko dla celów refleksji). Można go zainicjować za pomocą inicjatora we właściwości, jak w powyższym przykładzie. Ponadto w treści konstruktora typu deklarującego można przypisać właściwość tylko do pobierania, co powoduje, że wartość jest przypisywana bezpośrednio do pola bazowego:

Chodzi o bardziej zwięzłe wyrażanie typów, ale pamiętaj, że usuwa również ważną różnicę w języku między typami zmiennymi i niezmiennymi: właściwości automatyczne były skrótem dostępnym tylko wtedy, gdy chciałeś uczynić swoją klasę zmienną, a więc pokusa do domyślnego do tego było świetne. Teraz, dzięki właściwościom automatycznym tylko getter, pole gry zostało wyrównane między zmiennymi a niezmiennymi.

oraz w wersji roboczej specyfikacji języka C # 6.0 (uwaga: specyfikacja języka jest ostateczna, jeśli chodzi o Microsoft, ale nie została jeszcze zatwierdzona jako norma EMCA / ISO , stąd `` wersja robocza ''):

Właściwości wdrażane automatycznie

Właściwość zaimplementowana automatycznie (lub w skrócie właściwość auto) jest nieabstrakcyjną właściwością niebędącą zewnętrzną z treściami akcesorów tylko średnikami. Właściwości automatyczne muszą mieć metodę dostępu pobierania i opcjonalnie mogą mieć metodę dostępu set.

Gdy właściwość jest określona jako właściwość zaimplementowana automatycznie, ukryte pole zapasowe jest automatycznie dostępne dla właściwości, a metody dostępu są zaimplementowane w celu odczytu i zapisu w tym polu zapasowym. Jeśli właściwość auto nie ma ustawionego akcesora, pole zapasowe jest traktowane jako tylko do odczytu (pola tylko do odczytu). Podobnie jak w przypadku pola tylko do odczytu, w treści konstruktora klasy otaczającej można przypisać właściwość automatyczną tylko do pobierania. Takie przypisanie jest przypisywane bezpośrednio do pola zapasowego tylko do odczytu właściwości.

Właściwość auto może opcjonalnie mieć property_initializer, który jest stosowany bezpośrednio do pola zapasowego jako zmienna_inicjalizator (inicjatory zmiennych).

tomRedox
źródło
1
To jest głupi projekt. Powinien to być błąd czasu kompilacji, jeśli jest ustawiony w lokalizacji, w której właściwość jest traktowana jako tylko do odczytu.
Shiv
Dziwne dla mnie jest to, że nadal występuje błąd kompilatora, który mówi, CS0200 C# Property or indexer cannot be assigned to -- it is read onlygdy używasz zwykłej właściwości. Czy „właściwości automatyczne tylko do pobierania” są uważane za tylko do odczytu, czy nie?
Kyle Delaney
24

Jest to nowa funkcja w języku C # 6, która umożliwia tworzenie właściwości tylko do odczytu i inicjowanie ich wartości z konstruktora (lub w tekście podczas ich deklarowania).

Jeśli spróbujesz zmienić wartość tej właściwości poza konstruktorem, spowoduje to błąd kompilacji.

Jest tylko do odczytu w tym sensie, że po zainicjowaniu jego wartości (w tekście lub wewnątrz konstruktora) nie można zmienić jego wartości.

Yacoub Massad
źródło
Więc jakie jest wyjaśnienie? Jaka jest definicja gettera?
Noam B.
16

Gdyby nie było możliwe zainicjowanie właściwości tylko do odczytu z konstruktora (lub inicjatora właściwości automatycznej), byłoby to bezużyteczne, ponieważ zawsze zwróciłoby domyślną wartość dla swojego typu (0 dla liczb, null dla typów referencyjnych ). Ta sama semantyka stosowana do pól tylko do odczytu we wszystkich wersjach języka C #.

Aby zdefiniować prawdziwą właściwość tylko pobierającą (której nie można zainicjować z konstruktora), musisz określić, co zwraca jako część definicji:

public int Foo { get { return 5; } }

Lub, bardziej zwięźle w C # 6:

public int Foo => 5;
Douglas
źródło
Nie do końca prawda, właściwości tylko do odczytu są bardzo przydatne do hermetyzacji pewnych warunków w kodzie. Możesz napisać instrukcję if i prawie każdy kod, aby ocenić inne właściwości lub warunki i zwrócić odpowiednią wartość za każdym razem, gdy czytasz właściwość
sebagomez
3
@sebagomez: Nie jestem pewien, czy rozumiem twój punkt widzenia - czy to nie jest to, co pokazałem w moim przykładzie?
Douglas
5

„Właściwości implementowane automatycznie tylko do odczytu”

Przede wszystkim chcę wyjaśnić, że nieruchomość się podoba

public string FirstName { get; }

Nazywane są „właściwościami implementowanymi automatycznie tylko do odczytu”

Aby to sprawdzić, możesz uruchomić i sprawdzić powyższy kod w programie Visual Studio. Jeśli zmienisz wersję językową z C # 6,0 na C # 5,0, kompilator zgłosi następujący wyjątek Funkcja „właściwości implementowane tylko do odczytu automatycznie” nie jest dostępna w języku C # 5. Użyj wersji językowej 6 lub nowszej.

aby zmienić wersję językową C #, odwiedź tutaj

Teraz przechodzę do twojego drugiego pytania

„To jest tylko getter. Ale kiedy buduję konstruktora, mogę zmienić wartość ”

Firma Microsoft wprowadza „właściwości zaimplementowane automatycznie tylko do odczytu” w logice tylko do odczytu. Jak wiemy, słowo kluczowe „tylko do odczytu” jest dostępne w języku C # 1.0. używamy słowa kluczowego „readonly” jako modyfikatora w polu i to pole można przypisać na 2 sposoby, albo w momencie deklaracji, albo w konstruktorze w tej samej klasie.

W ten sam sposób wartość „właściwości implementowanych automatycznie tylko do odczytu” można przypisać na 2 sposoby

Way1 (w momencie zgłoszenia):

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

Way2 (w konstruktorze w tej samej klasie)

Person()
{
 FirstName  = "Banketeshvar";
}

Właściwość wyłącznie do odczytu

Jeśli szukasz nieruchomości wyłącznie do odczytu, wybierz to

public string FullName => "Manish Sharma";

teraz nie możesz przypisać wartości właściwości „FullName” z konstruktora. Jeśli spróbujesz to zrobić, zgłosi następujące wyjątki

„Nie można przypisać właściwości lub indeksatora„ Person.FullName ”- jest tylko do odczytu”

Banketeshvar Narayan
źródło
2
zauważ, że FullName => "foo bar" będzie sprawdzane KAŻDEGO RAZU.
JuFo
4

Funkcja Auto właściwość została dodana do języka podczas wydania C # 3.0. Umożliwia zdefiniowanie właściwości bez żadnego pola zapasowego, jednak nadal trzeba używać konstruktora, aby zainicjować te właściwości automatyczne do wartości innej niż domyślna. C # 6.0 wprowadza nową funkcję o nazwie auto property initializer, która umożliwia zainicjowanie tych właściwości bez konstruktora takiego jak poniżej:

Wcześniej konstruktor jest wymagany, jeśli chcesz tworzyć obiekty przy użyciu właściwości automatycznej i inicjować właściwość automatyczną do wartości innej niż domyślna, jak poniżej:

public class MyClass
{
    public int Foo { get; }

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

Teraz w C # 6,0 możliwość użycia inicjatora z właściwością auto oznacza, że ​​nie jest wymagany żaden jawny kod konstruktora.

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

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

Więcej informacji na ten temat znajdziesz tutaj

Rahul Nikate
źródło
1

Zadeklarowana zmienna readonlymoże być zapisana w konstruktorze, ale w językach, które honorują atrybut, nie można jej modyfikować po powrocie konstruktora. Ten kwalifikator został dostarczony jako funkcja języka, ponieważ często jest niezbędny dla pól, których wartości będą się różnić w zależności od parametrów konstruktora (co oznacza, że ​​nie można ich zainicjować przed uruchomieniem konstruktora), ale nie będzie trzeba ich zmieniać po powrocie konstruktora, ale tak było użyteczne tylko dla zmiennych ujawnionych jako pola. Semantyka readonlypól kwalifikowanych byłaby w wielu przypadkach idealna dla członków publicznych, z wyjątkiem tego, że często lepiej jest, aby klasy ujawniały elementy członkowskie - nawet niezmienne - jako właściwości, a nie pola.

Tak jak istnieją właściwości automatyczne do odczytu i zapisu, które umożliwiają klasom ujawnianie właściwości modyfikowalnych tak łatwo, jak zwykłe pola, istnieją właściwości automatyczne tylko do odczytu, które umożliwiają klasom ujawnianie niezmiennych właściwości tak łatwo, jak readonlypola kwalifikowane. Tak jak readonlypola -qualified można zapisać w konstruktorze, tak samo jest z właściwościami tylko do pobierania.

supercat
źródło