Tel: 600283424
Właściwości i akcesory C# – Properties & Accessors
PerfectSoft > Baza wiedzy > C# > Właściwości i akcesory C# – Properties & Accessors

Właściwości i akcesory C# – Properties & Accessors

Właściwości i akcesory

Dzielimy się z Wami bezpłatnie wiedzą programistyczną.

Jeżeli doceniacie naszą pracę możecie nas wesprzeć dobrowolną wpłatą:

DONATE

EN

Właściwości i akcesory są ze sobą tak mocno skorelowane, że nie sposób omawiać je oddzielnie. Właściwość (ang. Properties – czasem można spotkać się z określeniem wywodzącym się z angielskiej nazwy „propercje” lub skróconym własność) jest specjalną konstrukcją, łączącą aspekty zarówno pól jak i metod. Pozwala ona na dostęp do zmiennych prywatnych obiektu, poprzez specjalne metody będące akcesorami. Istotną właściwością jest to, że użytkownik obiektu widzi je tak, jak zwykłe zmienne udostępnione publicznie. Pozwalają wykonywać zwykłe operacje tak jak na zmiennej, a także pozwalają na wykorzystanie ich w interfejsach.


Akcesory są odpowiednikiem metod stosowanych od dawna w językach programowania obiektowego, pozwalających na odczyt jak i na zapis prywatnych pól klasy. Ze względu na hermetyzację, wszystkie pola w klasie powinny być ukrywane, a ewentualny dostęp do nich realizowany poprzez metody dodatkowo zapewniające kontrolę wprowadzanych danych. Metody te nazywane są „setterami” i „getterami”.


Spis treści



Akcesory, a settery i gettery


Składnia kodu korzystającego z setterów i getterów została zaprezentowana poniżej:


class Wartosci
{
  private int liczba;

  public int get_liczba()
  {
    return liczba;
  }

  public void set_liczba(int iLiczba)
  {
    liczba = iLiczba;
  }
}

Przykład wydaje się wygodny i spójny, ale metody nie są ze sobą powiązane, mogą znajdować się w różnych miejscach rozbudowanej klasy, a w przypadku wielu zmiennych, może to się rozrosnąć do zajmującego wiele linii kodu. Korzystanie z takich metod wygląda następująco:


static void Main(string[] args)
{
  Wartosci wart = new Wartosci();

  //Ustawianie wartości
  wart.set_liczba(12);

  //Odczyt wartości
  MessageBox.Show(wart.get_liczba());
}

Akcesory realizują dokładnie to samo zadanie, ale korzystanie ze zmiennych staje się wygodniejsze. Poniżej znajdują się zaprezentowane wcześniej przykłady z wykorzystaniem akcesorów:


class Wartosci
{
  private int _liczba;

  public int liczba
  {
    get
    {
      //uruchamiany gdy wartość jest odczytywana
      return _liczba;
    }
    set
    {
      //uruchamiany gdy wartość jest ustawiana
      _liczba = value;
    }
  }
}

W kodzie znajdują się metody get oraz set, są one odpowiednikiem metod z poprzedniego przykładu. Dodatkowo, metody te dla kompilatora faktycznie powstają. W momencie zadeklarowania właściwości o nazwie liczba, kompilator zarezerwował nazwy metod get_liczba oraz set_liczba, więc nie ma możliwości zdefiniowania ich ponownie, a próba zakończy się błędem:


Type 'Wartosci’ already reserves a member called 'get_liczba’ with the same parameter types


Ciekawym elementem właściwości jest słowo kluczowe value. Jest to zmienna tymczasowa pozwalająca dokonać operacji na aktualnie wprowadzanej wartości np. podczas przypisania liczba = 10; zmienna value przyjmie wartość 10.


Korzystanie ze zmiennej zadeklarowanej poprzez właściwości wygląda następująco:


static void Main(string[] args)
{
  Wartosci wart = new Wartosci();

  //Ustawianie wartości
  wart.liczba = 12;

  //Odczyt wartości
  MessageBox.Show(wart.liczba);
}

Tak jak zostało to wspomniane na wstępie artykułu, operacje odbywają się tak jak na zwykłej zmiennej udostępnionej publicznie.


Konstrukcja właściwości


Właściwości mogą posiadać tylko akcesor pobierania wartości, tylko akcesor ustawiania wartości lub oba akcesory na raz. Pozwala to na uzyskanie zmiennych z ograniczonym dostępem – zmienne read-only, write-only lub read-write. Akcesor get zawsze musi zwracać wartość poprzez słowo kluczowe return.


Akcesor get uruchamiany jest w momencie odczytu wartości, akcesor set w momencie ustawienia wartości. Wykonywane są wtedy wszystkie operacje zawarte w nawiasach klamrowych akcesora. Operacje umieszczane do wykonania w akcesorach nie powinny być zbytnio skomplikowane. Ponadto niepoprawnym stylem programowania jest zmiana wartości pola w akcesorze get, np.:


public int Liczba
{
  get
  {
    return liczba++; //Nie powinno się tego stosować
  }
}

Właściwość składa się tylko z dwóch elementów: set oraz get, bez możliwości pobierania parametrów. Nie jest dozwolone stosowanie dodatkowych pól,metod i kolejnych właściwości. Właściwości muszą posiadać chociaż jeden akcesor.


Deklaracja skrócona


Zamiana zwykłych metod na właściwość pozwoliła częściowo uporządkować kod, ale nie skróciła go znacząco. Ponieważ często stosowane akcesory, tak jak w przedstawionych wcześniej przykładach, nie zmieniają wartości, a jedynie pośredniczą w dostępie do niej, wprowadzono (od wersji C# 3.0) deklarację skróconą.


Pozwala ona zredukować poniższy kod:


class Wartosci
{
  private int _liczba;
  public int liczba
  {
    get
    {
      return _liczba;
    }
    set
    {
      _liczba = value;
    }
  }
}

w bardzo krótki zapis:


class Wartosci
{
  public int liczba{get;set;}
}

Oba zapisy są sobie równe, ponieważ kompilator rozwinie skróconą deklarację, a także niejawnie utworzy pole prywatne, do którego dostęp realizuje zapisana właściwość. Pozwala to znacząco skrócić zapis i zwiększyć przejrzystość kodu.


Podsumowując. Zapis powyższej deklaracji skróconej o nazwie liczba niejawnie utworzy prywatną zmienną oraz metody o nazwach get_liczba() i set_liczba() pozwalające na dostęp do wartości zmiennej.


Operatory i właściwości


Właściwości w przeciwieństwie do zwykłych metod pozwalają także na stosowanie operatorów wymagających jednocześnie odczytu i zapisu wartości. Operacje te działają bez konstruowania dodatkowych deklaracji. Poniżej przedstawione są operacje na wartościach z poprzednich przykładów i informacja, który akcesor został uruchomiony:


static void Main(string[] args)
{
  Wartosci wart = new Wartosci();

  int m = wart.liczba; //Blok get dla Wartosci
  wart.liczba = m; //Blok set dla Wartosci
  wart.liczba -= 12; //Blok get i set dla Wartosci
  wart.liczba += 18; //Blok get i set dla Wartosci
}

Kontrola wartości (Właściwości i akcesory)

Wartości pól, które zostały udostępnione publicznie, nie jest w żaden sposób kontrolowana. Może to prowadzić do poważnych błędów funkcjonowania klasy, a nawet całego programu. Błędy prowadzące do szybkiego wysypania się programu są o wiele lepsze niż długotrwałe, nie dające o sobie poznać błędy wpływające na wyniki. Znalezienie takiego błędu wymagać będzie wiele czasu i często prześledzenia większości napisanego kodu. Prostymi przykładami wartości wymagających kontroli są: sekundy/minuty (1-60), godziny (1-12/1-24), oceny (1-6), oceny na studiach (2; 3; 3,5; 4; 4,5; 5) i wiele innych. Przykład w kodzie:


class Wartosci
{
  private int _godzina;

  public int godzina
  {
    set
    {
      if (value >= 1 && value <= 24)//dla zegara 24 godzinnego
      _godzina = value;
    }
  }
}

Kontrola wprowadzanych wartości w kodzie korzystającym z obiektów klasy może prowadzić do wielu niepożądanych skutków. Kod musi być powtarzany w każdym miejscu, gdzie dane są wprowadzane, programista może o tym zapomnieć lub zrobić to nieprawidłowo, użytkownik klasy może specjalnie doprowadzić do zapisu błędnych wartości. Wymienione powody są wystarczające, by zadbać o poprawność zapisywanych danych. Idealnym miejscem na kontrolę wprowadzanych wartości jest akcesor set. Pozwala nie tylko na zdefiniowanie wartości w jednym, łatwym do zlokalizowania miejscu, ale także na szybką zmianę zasad w całym programie np. gdy zakres ocen zmieniłby się na 1-10.


Akcesory pełnią jeszcze jedną ważną funkcję związaną z kontrolą wartości. Odczytywane i zapisywane dane nie muszą być zwykłą zmienną. Co w przypadku, gdy pracujemy z bazami danych i dane pole jest zapisane w takiej bazie? Akcesor get w takim przypadku może realizować pobieranie danej wartości, a akcesor set sprawdzanie czy wartość jest zgodna z typem pola w bazie danych i zapisem, gdy jest ono poprawne. Dla programisty korzystającego z klasy nie jest istotne połączenie z bazą, on widzi wartość tak jak zwykłą zmienną. Praca nad wspólnym kodem przez wielu programistów jest także jednym z wielu powodów skłaniających do korzystania z właściwości.


W akcesorach można korzystać z innych metod. Jeżeli sprawdzanie wartości podlega tym samym warunkom, jak w przypadku sekund i minut, to możliwe jest przygotowanie metody dokonującej sprawdzenie wartości oraz późniejsze korzystanie z nich w akcesorach.

Do czego stosować właściwości?


Jeżeli jeszcze nie zdołałem Cię przekonać do stosowania właściwości, to przytoczę kolejne dwa przykłady.


Przykład 1:


Załóżmy, że zmienna (typu int) w klasie jest wynikiem operacji, a jej wartość jest częścią nazwy zapisywanego pliku. Po zmianach wprowadzonych do programu konieczne jest dopisanie przedrostka w nazwie w postać:


"wyniki_" + zmienna.ToString();

Zmiana nazewnictwa w całym programie może zając sporo czasu, a zawsze istnieje niebezpieczeństwo pominięcia jakiejś wartości. Stosując od początku właściwości cała operacja ograniczyłaby się do jednej zmiany w akcesorze get.


Przykład 2:


W działającym programie powstała konieczność zliczania ilości wprowadzanych zmian w zmiennej „liczba”. By zrealizować taką funkcjonalność należałoby znaleźć wszystkie miejsca, gdzie zmienna „liczba” otrzymuje nowe wartości i zwiększanie w nich licznika. Stosowanie właściwości pozwala na zrealizowanie tego poprzez uzupełnienie akcesora set o dodatkową linię:


licznik++;

Właściwości i akcesory – Techniczne aspekty


  • – Właściwości mogą mieć modyfikatory dostępu: public, private, protected oraz internal. Zarówno akcesory mogą mieć różne modyfikatory dostępu. Dzięki takiemu zastosowaniu odczyt zmiennej może być publiczny, a więc dostępny z zewnątrz klasy, a zapis jej wartości private lub protected.
  • – Właściwości mogą być statyczna, deklarowane za pomocą słowa kluczowego static. Dzięki temu właściwość jest dostępna nawet bez instancji klasy – obiektu.
  • – Właściwości mogą być wirtualne, deklarowane za pomocą słowa kluczowego virtual. Pozwala to na zmianę zachowania właściwości w klasach pochodnych poprzez słowo kluczowe override.
  • – Właściwości nie mogą być const, ponieważ nie ma takiej potrzeby. Dodatkowo w C# nie są obsługiwane const metody, właściwości i zdarzenia.
  • – Właściwości nie są zmiennymi, a więc nie ma możliwości przekazywania ich poprzez słowa kluczowe ref lub out. Jest to całkowicie uzasadnione, ponieważ właściwość jako zbiór metod nie reprezentuje konkretnego miejsca w pamięci.
  • – Właściwość zezwala na założenie breakpointów, co jest zrozumiałe, gdyż dla kompilatora są to zwykłe metody.
  • – Właściwości można umieszczać w interfejsach – są to metody, pola w interfejsach są zabronione. Akcesory właściwości nie mogą posiadać implementacji w interfejsie, dlatego ich zapis kończy się średnikiem: get; oraz set;
  • – Właściwości abstrakcyjne istnieją tylko w klasach abstrakcyjnych.

Zalety właściwości


Podsumowując zalety stosowania właściwości, jako główne wymienić można:


  • – Przejrzystość kodu.
  • – Dopuszczenie skróconego zapisu – deklaracji skróconej.
  • – Hermetyzacja kodu.
  • – Kompatybilność z Interfejsami.
  • – Wygodne zarządzanie aplikacją.
  • – Kontrola poprawności wartości zmiennych.
  • – Operowanie na metodach tak jak na zwykłej zmiennej, z wykorzystaniem operatorów +, -, =, +=, -= …
  • – Wiele innych zapewniających wygodę, bezpieczeństwo i skracające kod.

×
Czy życzą sobie Państwo kontaktu z naszej strony?
TOP