Programowanie w języku C#

Właściwości

  • 2010-07-11 23:45
  • 2 komentarze
  • 17616 odsłon
  • 4/6
Właściwości to specjalna konstrukcja języka C# która symuluje zachowanie pól klasy lub struktury, a w rzeczywistości jest trochę podobna do funkcji.

Przykład deklaracji właściwości:
class Klasa
{
        public int Wlasciwosc
        {
             get
             {
                 // co ma zostać zwrócone przy odwołaniu do tej właściwości
             }
             set
             {
                 // co ma stać się z wartością przypisaną do tej właściwości
             }
        }
}


Taka konstrukcja (czysta właściwość) jest rzadko stosowana, znacznie częściej tworzy się właściwości współpracujące z konkretnym polem klasy.

Przykład:

class Klasa
{
    private int pole; // deklaracja właściwego pola klasy. Jest ono - jak nakazuje dobry zwyczaj programowania obiektowego - ukryte przed obiektami z zewnątrz.
 
    public int Wlasciwosc // właściwość
    {
        get // blok gettera
        {
                return pole; // nie robi nic oprócz zwrócenia wartości pola.
        }
        set // blok settera
        {
                pole=value; // nie robi nic oprócz przypisania do pola.
        }
    }
}


Od C# 3.0 możliwy jest również zapis skrócony (kod równoważny)

class Klasa
{
    public int Property { get; set; }
}


który oznacza właśnie właściwość zachowującą się jak zwykłe pole. Przez kompilator ten kod jest rozwijany do

[CompilerGenerated]
private int <Property>k_BackingField;
 
public int Property
{
    get
    {
         return this.<Property>k_BackingField;
    }
 
    set
    {
        this.<Property>k_BackingField = value;
    }
}


W obydwóch przypadkach jest to maksymalnie okrojona właściwość która w zachowaniu nie różni się niczym od publicznego pola. Jednak bloki get i set wykonują się jak w normalnej metodzie, i nic nie stoi na przeszkodzie żeby je jakoś wzbogacić.

value jest słowem kluczowym mającym specjalne znaczenie jedynie w bloku settera właściwości. Przedstawia on w sposób symboliczny wartość przypisywaną właściwości".

Właściwość która również nie robi niczego pożytecznego, ale demonstruje przykładowe zastosowanie:
class Klasa
{
    private int pole; // deklaracja właściwego pola klasy. Jest ono - jak nakazuje dobry zwyczaj programowania obiektowego - ukryte przed obiektami z zewnątrz.
 
    public int Wlasciwosc // właściwość
    {
        get // blok gettera
        {
            Console.WriteLine("Ktoś pobiera moją wartość!");
                return pole; // zwraca wartość pola.
        }
        set // blok settera
        {
            Console.WriteLine("Ktoś zmienia moją wartość!");
                pole=value; // przypisuje wartość do pola.
        }
    }
}


Można też tworzyć pola tylko do odczytu nie definiując metody set.

Różnice między właściwościami i polami, rzeczywista reprezentacja właściwości



Na pierwszy rzut oka zmienna:

int Count;


i właściwość (zapis skrócony):
int Count {get; set;}


wyglądają podobnie. Na drugi zresztą też, bo odwoływanie do obydwóch jest takie same, czyli

int i = Count;
Count = i;


Tak naprawdę jednak property (czyli te gettery i settery) mają za zadanie symulować konstrukcje znane np. z C++

private:
    int count;
public:
    int getCount() { return count; }
    void setCount(int value) { count = value; }



Ok, wracamy do C#. I rzeczywiście - na poziomie kodu "maszynowego" (czyli w przypadku C# oczywiście kodu pośredniego) zwykła zmienna zostanie zapisana (w przenośni, nie na poziomie IL)

int Count;


co innego jeśli użyjemy właściwości. zapis int Count {get; set;} da nam w wyniku skądinąd znajomą konstrukcję...

public int get_Count();
public int set_Count(int value);


I w rzeczywistości odwołanie się do zmiennej również jest intuicyjne - czyli zmienna Count = 10; da nam to samo w kodzie wynikowym, gdy tymczasem i = property Count; da w wyniku i = get_Count(); Nie musisz mi wierzyć na słowo, dodaj do dowolnego swojego kodu deklarację funkcji z przedrostkiem get_ tak żeby kolidowała z nazwą właściwości a otrzymasz błąd kompilacji (Type (typ)' already reserves a member called 'get_(nazwa property)' with the same parameter types).

Konsekwencją powyższego (właściwości są metodami) jest też to że można bezproblemowo zakładać na nie breakpointy - nie jest to możliwe w przypadku pól. Tłumaczy to też dlaczego właściwości można umieszczać w interfejsach, a pola już nie.

Jak wiadomo właściwości (czyli jakiekolwiek reagowanie na zmianę / pobranie zmiennej) są jednak czasami potrzebne.  W niewielkim projekcie zmienienie zmiennej w właściwość nie powinno być trudne (po prostu wystarczy dopisać {get;set;}) - ale w sporym projekcie może być gorzej, jeśli np. zmienna w jednej klasie zostanie zmieniona we właściwość to wszystkie pozostałe biblioteki korzystające z tej klasy będą musiały być ponownie skompilowane (bo nie znajdą zmiennej nazwanej - zostawmy już to hipotetyczne - Count, a nic ich nie będzie obchodzić metoda get_Count(). ).
Dlatego właśnie dobrym zwyczajem jest też izolowanie pól klasy od świata zewnętrznego.

2 komentarze

pustypawel 2015-10-31 18:48

public int get_Count();
public int set_Count(int value);

nie powinno być:

public int get_Count();
public void set_Count(int value);

Brak avatara
xczar0 2014-04-06 11:26

Słabe wytłumaczenie.