TOC

This article has been localized into Polish by the community.

Klasy:

Właściwości

W poprzednim artykule omawialiśmy pola. Można je porównać do globalnych zmiennych dla danej klasy, które są dostępne dla wszystkich jej metod. Oprócz tego wspomnieliśmy o tym, że inne klasy również mogą mieć do nich dostęp, jeżeli pola te są określone jako public (publiczne), ale takie rozwiązanie zwykle nie jest zalecane. Jeżeli chcesz, aby dostęp do zmiennych/pól był możliwy spoza twojej klasy, powinieneś zamiast tego użyć właściwości.

Kiedy zadeklarujesz pole jako public, zezwalasz na całkowity dostęp do niego z zewnątrz - inne klasy mogą robić z nim, co tylko im się podoba, nawet bez powiadomienia o tym deklarowanej klasy. Właściwości dają nieco kontroli deklarowanej klasie przez możliwość sprecyzowania, czy pole ma być tylko do odczytu lub zapisu oraz możliwość sprawdzania poprawności oraz manipulacji wprowadzanymi danymi, zanim zostaną one zwrócone albo przypisane do pola.

Właściwości wyglądają jak połączenie pola i metody - są one deklarowane tak jak pola, za pomocą widoczności, typu danych i nazwy, ale mają także treść (body) jak metoda, pozwalającą na kontrolowanie jej przeznaczenia:

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Zwróć uwagę na specjalne słowa kluczowe: get oraz set. Używane są one jedynie we właściwościach, by móc kontrolować odczyt (get'ing) i zapis (set'ing) pola. Możesz tworzyć pola, używając tylko samego get LUB set, co sprawi, że dane pole będzie przeznaczone jedynie do zapisu bądź jedynie do odczytu. Możesz także kontrolować widoczność implementacji get lub set, by dla przykładu stworzyć właściwość, która może być odczytana z zewnątrz (public), ale zmodyfikowana wyłącznie z wewnątrz deklarowanej klasy (private).

Możesz też zauważyć, że odwołaliśmy się do pola nazwanego _name. Musi być ono wcześniej zadeklarowane w klasie, by właściwość mogła z niego prawidłowo skorzystać. Przykładowy wzór deklaracji pól z właściwościami wygląda tak:

private string _name = "John Doe";

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Teraz widzisz jak pola i właściwości działają razem: Metoda get zwraca wartość pola _name, podczas gdy metoda set przypisuje do pola _name podaną wartość. W metodzie set używa się specjalnego słowa kluczowego value, które w tym przypadku definiuje wartość przypisaną właściwości.

To co już poznaliśmy to są dopiero absolutne podstawy i na razie nie zrobiliśmy niczego, co nie mogłoby być wykonane poprzez zwykłe publiczne pole. Ale w pewnym momencie możesz zachcieć mieć większą kontrolę nad tym, jak inne klasy mogą pracować z polem _name. Jako że zaimplementowałeś je jako właściwość możesz swobodnie zmodyfikować implementację nie przeszkadzając żadnemu używającemu klasy. Na przykład, możemy zmodyfikować właściwość Name, by wyglądała tak:

private string _name = "John Doe";

public string Name
{
	get 
	{
		return _name.ToUpper();
	}
	set 
	{
		if(!value.Contains(" "))
			throw new Exception("Please specify both first and last name!");
		_name = value; 
	}
}

Metoda get teraz sprawia, że wartość jest zawsze zwracana WIELKIMI LITERAMI niezależnie od wielkości liter w polu _name. Do metody set dodaliśmy kilka linijek, by sprawdzić czy wartość jaką nadajemy zawiera spację, ponieważ chcemy by pole _name zawierało zarówno imię, jak i nazwisko. Jeśli nie będzie, zostanie zgłoszony wyjątek. Ten przykład jest dość uproszczony, ale powinien w pełni pokazać poziom kontroli jaki zyskujesz, gdy używasz właściwości.

Właściwości tylko do odczytu

Większość właściwości jakie zobaczysz w przykładach będzie zarówno do odczytu, jak i do zapisu, ponieważ to jest najpowszechniejsze użycie właściwości. Nie zawsze jednak musi tak być. Zacznijmy od tego, że możesz zadeklarować właściwość tylko z metodą get, jak poniżej:

private string _name = "John Doe";

public string Name
{
	get { return _name; }
}

W tym przypadku nie możesz zmienić już właściwości "Name". Można jedynie ją odczytać, a gdy spróbujesz zmienić jej wartość, kompilator wypluje błąd. Wciąż jednak możesz zmienić wartość w środku klasy, zwyczajnie przypisując nową wartość do pola "_name". Robiąc to jednak w ten sposób, pozbawiasz siebie jednej z największych zalet właściwości - kontroli jakie wartości będą akceptowane. Tak jak już sobie powiedzieliśmy, metoda set jest świetnym sposobem by zweryfikować przypisywane wartości, ale jeśli przypiszesz nową wartość pola _name z różnych miejsc, jako że właściwość jest tylko do odczytu, nie masz już możliwości dokonywanie tej weryfikacji.

Na szczęście C# dostarcza nam na to rozwiązanie: Możesz zdefiniować metodę set dla właściwości, a następnie ograniczyć jej widoczność używając słów kluczowych private lub protected. Rozwiązanie to będzie dzieliło najlepsze cechy z obu poprzednich, bo będzie można zarówno ograniczyć przypisywanie wartości tylko dla wnętrza klasy (lub też dziedziczących przy użyciu "protected"), jak i wciąż weryfikować tą wartość przez metodę set.

private string _name = "John Doe";

public string Name
{
	get { return _name; }

	private set
	{
		if(IsValidName(value))
			this._name = value;
	}
}

public bool IsValidName(string name)
{
	return name.EndsWith("Doe");

}

Kluczową różnicą jest tu po prostu słowo kluczowe "private" tuż przed słowem kluczowym "set". Tak jak wspomniano, private można zastąpić też m. in. słówkami protected lub internal, w zależności od potrzeby.

Właściwości zaimplementowane automatycznie

Niekiedy nie masz potrzeby całkowitej kontroli nad polem, a niewygodnie jest implementować zarówno pole, jak i właściwość, kiedy nie przekracza się użycia jakie zobaczyliśmy w pierwszym przykładzie. Możesz się kusić, by po prostu zadeklarować swoją zmienną jako publiczne pole i uniknąć tej całej gehenny. Nie rób jednak tego! Szczęśliwie, Microsoft dodał właściwości zaimplementowane automatycznie do C# 3.0, które oszczędzi nam kilka linijek kodu. Spójrz tylko na tą różnicę:

Zwykła właściwość z zadeklarowanym prywatnym polem:

private string _name;

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Właściwość zaimplementowana automatycznie, działanie programu nie ulega zmianie:

public string Name { get; set; }

Zauważ, że metody get i set są puste, a także nie jest deklarowane żadne prywatne pole - innymi słowy, możemy uzyskać taki sam efekt jak w pierwszym przykładzie pisząc tylko jedną linijkę kodu! Miej jednak świadomość, że podczas egzekucji programu prywatne pole wciąż będzie istnieć. Zostanie ono - jak nazwa wskazuje - automatycznie zaimplementowane przez kompilator. Jeśli tylko uznasz, że potrzebujesz więcej kontroli nad tą właściwością, możesz po prostu zmienić ją na zwykły układ pole/właściwość z zamierzoną implementacją metod get i set.

Zauważ, że używając właściwości zaimplementowanych automatycznie, wciąż masz do dyspozycji ważną mechanikę jak przy tych zwykłych. Możesz pominąć słowo kluczowe set i tym samym, stworzyć właściwość tylko do odczytu, np. taką jak poniższa:

public string ReadOnlyProperty { get; }

Właściwość zaimplementowana automatycznie nie może być jednak właściwością tylko do zapisu.

Właściwości zaimplementowane automatycznie z wartościami domyślnymi

Do wersji 6.0 nie mogłeś zdefiniować domyślnej wartości dla właściwości zaimplementowanej automatycznie - trzeba było tworzyć pole prywatne, które pozwoliłoby na zainicjowanie zmiennej z wartością.

private string _name = "John Doe";

public string Name
{
	get { return _name; }
	set { _name = value; }
}

Ale w wersji 6.0 Microsoft w końcu dodał możliwość zainicjowania właściwości zaimplementowanej automatycznie z domyślną wartością, jak poniżej:

public string Name { get; set; } = "John Doe";

Właściwości z definicją treści wyrażeń

Inną zawartość powiązaną z właściwościami, Microsoft dodał w C# 6.0 i 7.0. Są to definicje treści wyrażeń. Pozwalają one po prostu na zapis wyrażenia dla twoich właściwości i metod w jednej linijce - w poniższym przykładzie, widzimy jak można ich użyć, aby zaimplementować metody get/set tak, by zajmowały mniej miejsca i wymagały nieco mniej pisania:

private string name;
public string Name
{
	get => name;
	set => name = value;
}

Jeśli właściwość jest tylko do odczytu, zapis może być jeszcze krótszy:

public string Name => "John Doe";

Oczywiście ten sposób także działa, gdy musimy coś jeszcze wykonać przed zwróceniem wartości, jak w poniższym przykładzie:

public string Name { get; set; } = "John Doe";

public string FirstName => this.Name.Substring(0, this.Name.IndexOf(" "));

Jak widać, umożliwia to definiowanie metody get bez użycia słów kluczowych get i return, jednocześnie pozwalając na zapisanie tego wszystkiego w tylko jednej linijce.

Podsumowanie

Właściwości dają twoim klasom większą kontrolę nad tym, jak pola mogą być udostępniane i modyfikowane. Powinny być one użyte zawsze, gdy chcesz dać dostęp do pola spoza klasy, w której zostało ono zadeklarowane.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!