Właściwości zwane też czasami własnościami występują w języku C#. Jest to ułatwienie i skrócenie zapisu metod dostępu do zmiennej prywatnej.
Przykładowa właściwość:

private string color; // deklaracja zmiennej

    public string Color {
        get { return color; }
        set { color = value; }
    }

Właściwość jest podobna do metody lecz nie posiada w swej definicji nawiasów (). Jej nazwa musi się różnić od nazwy zmiennej np. poprzez użycie dużej litery. Typ właściwości musi się zgadzać z typem zmiennej, której się ona tyczy. Mamy w niej dwa akcesory:
-get, który zwraca nam za pomocą słowa kluczowego return wartość naszej zmiennej prywatnej.
-set, który ustawia nam wartość dla zmiennej za pomocą słowa kluczowego value, oznaczające wartość wprowadzaną.

Nasza klasa Car z właściwościami:

class Car {
    private string color;
    private string carBrand; 
    private double price = 0;

    public double Price {
        get { return price; }
        set { price = value; }
    }

    public string Color {
        get { return color; }
        set { color = value; }
    }

    public string CarBrand {
        get { return carBrand; }
        set { carBrand = value; }
    }
    
    public void ViewInformation() {
        Console.WriteLine("Kolor samochodu: " + color);
        Console.WriteLine("Marka samochodu: " + carBrand);
        Console.WriteLine("Cena samochodu: " + price);
    }
}

Dodajmy teraz do właściwości walidację danych:

class Car {
    private string color;
    private string carBrand;
    private double price = 0;

    public double Price {
        get { return price; }
        set {
            if (value < 0)
                price = value;
            else
                price = (-1) * value;
        }
    }

    public string Color {
        get { return color; }
        set { color = value.ToUpper(); }
    }

    public string CarBrand {
        get { return carBrand; }
        set { carBrand = value; }
    }

    public void ViewInformation() {
        Console.WriteLine("Kolor samochodu: " + color);
        Console.WriteLine("Marka samochodu: " + carBrand);
        Console.WriteLine("Cena samochodu: " + price);
    }
}

Nie zaleca się stosowania rozbudowanych walidacji we własnościach. Gdy mamy taką potrzebę wtedy lepiej zastosować dodatkową metodę odpowiedzialną za tą funkcjonalność.

IntelliSense w Visual Studio oznacza własności ikoną:

cz2-1

Rys. Wybór własności z obiektu klasy Car.

Zmienna publiczna oznaczona jest niebieskim ikoną:

cz2-2

Rys. Wybór publicznej zmiennej z obiektu.

W kodzie klienta wywołanie własności wygląda jak przypisywanie lub odczytanie wartości do zmiennej publicznej naszej klasy:
Cały kod aplikacji:

using System;
class Car {
    private string color;
    private string carBrand;
    private double price = 0;

    public double Price {
        get { return price; }
        set {
            if (value < 0)
                price = value;
            else
                price = (-1) * value;
        }
    }
    public string Color {
        get { return color; }
        set { color = value.ToUpper(); }
    }

    public string CarBrand {
        get { return carBrand; }
        set { carBrand = value; }
    }

    public void ViewInformation() {
        Console.WriteLine("Kolor samochodu: " + color);
        Console.WriteLine("Marka samochodu: " + carBrand);
        Console.WriteLine("Cena samochodu: " + price);
    }
}
class Program {
    static void Main() {
        Car auto = new Car();
        auto.CarBrand = "Fiat";
        auto.Color = "black";
        auto.Price = -120000;
        auto.ViewInformation();
        Console.ReadLine();
    }
}

Oto rezultat działania programu:

cz2-3

Rys. Wyświetlenie stanu obiektu

Rezultat działania aplikacji jest identyczny jak z zastosowaniem metod dostępu. Dostęp do pól w klasie poprzez zastosowanie właściwości jest bardziej „naturalny” niż poprzez stosowanie metod.

Zapis skrócony

Dla własności możemy stosować zapis skrócony który wygląda następująco:

  public int CarYearOfProduction {
        get;
        set;
    }

W tym przypadku nie możemy przypisać żadnych reguł dla danych, które chcemy wprowadzić lub wypisać. Nie musimy też tworzyć zmiennej prywatnej, która będzie przechowywać wartość dla własności. W skróconym zapisie musimy użyć akcesora get oraz set. Więc czemu nie ustawić modyfikatora dostępu na publiczny?

Są dwa powody pierwszym z nich jest możliwość nadpisania własności:

    public class KlasaA {
        public virtual int Wiek; // nie da się
        public virtual int Wzrost { get; set; }
    }

    public class KlasaB : KlasaA {
        public override int Wiek; // nie da się
        private int _wiek;
        public override int Wzrost {
            get { return GetWiek(); }// możemy zrobić co chcemy
            set { ValidateWiek(value); }// możemy zrobić co chcemy
        }
        private int GetWiek() {
            return _wiek + 1000;
        }
        private void ValidateWiek(int value) {
            if (value < 0)
                value = value * -1;
            _wiek = value;
        }
    }

Drugim deklaracja interface:

    public interface ISuperWiek {
        //możemy
        int Wiek { get; set; } 
        int Wiek2 { get; }
        int Wiek3 { set; }
        //nie możemy
        int Wiek4;
    }

Pole tylko do odczytu lub zapisu

Gdy chcemy aby pole było tylko do odczytu, nie implementujemy w właściwości akcesora set. Natomiast gdy chcemy aby można było wprowadzić wartość do zmiennej, ale jej nie uzyskać w kodzie klienta wystarczy nie implementować w właściwości akcesora get. Zobaczmy prosty przykład:
Zmieńmy kod naszej klasy Car tak aby zablokować możliwość przypisania do zmiennej ceny auta z obiektu klasy Car. Zablokujmy także możliwość zmiany marki samochodu, ustawimy dla niej standardową wartość:

class Car {
    private string color;
    private string carBrand = "BMW";

  
    private double price = 0;
    public double Price {      
        set {
            if (value < 0)
                price = value;
            else
                price = (-1) * value;
        }
    }
    public string Color {
        get { return color; }
        set { color = value.ToUpper(); }
    }

    public string CarBrand {
        get { return carBrand; }  
    }

    public int CarYearOfProduction {
        get;
        set;
    }

    public void ViewInformation() {
        Console.WriteLine("Kolor samochodu: " + color);
        Console.WriteLine("Marka samochodu: " + carBrand);
        Console.WriteLine("Cena samochodu: " + price);
        Console.WriteLine("Rok produkcji:" + CarYearOfProduction);
    }
}  

Spróbujmy teraz przypisać wartość dla pola odpowiedzialnego za przechowywanie marki samochodu:

class Program {
static void Main() {
        Car auto = new Car();
        auto.CarBrand = "Fiat";
        auto.Color = "black";
        auto.Price = -120000;
        auto.ViewInformation();
        Console.ReadLine();
        
    }}

Kompilator zgłosi nam błąd:

cz2-4

Rys. Błąd zgłoszony przez kompilator

Pole odpowiedzialne za markę w klasie Car jest tylko do odczytu.

Sprawdźmy teraz czy udało nam się zablokować możliwość odczytu zmiennej odpowiedzialnej za przechowywanie wartości ceny w klasie Car:

class Program {
static void Main() {
        double tempPrice = 0;
        Car auto = new Car();      
        auto.Price = -120000;   
        tempPrice = auto.Price; 
        Console.ReadLine();
        
    }}

Kompilator zgłosi nam błąd:

cz2-5

Rys. Błąd zgłoszony przez kompilator

Zmienna odpowiedzialna za cenę w klasie Car jest tylko do zapisu.
W ten prosty sposób możemy kontrolować czy użytkownik ma mieć uprawnienia do zapisu i odczytu w danym polu czy tylko do jednej z tych opcji.
Oczywiście nie tworząc właściwości lub metod dostępu dla zmiennej z modyfikatorem private nie będzie ona dostępna z poziomu obiektu danej klasy. Czyli „ukrywamy” ją przed użytkownikiem a mamy możliwość wykorzystania jej w obliczeniach wewnątrz ciała klasy.

„Ukrywanie” metod

W przypadku gdy chcemy aby któraś z naszych metod nie była dostępna z poziomu obiektu danej klasy, ustawiamy jej modyfikator dostępu na private. Zobaczmy przykład:
Zmieńmy modyfikator dostępu dla metody ViewInformation() z public na private w klasie Car:

Private void ViewInformation() {
        Console.WriteLine("Kolor samochodu: " + color);
        Console.WriteLine("Marka samochodu: " + carBrand);
        Console.WriteLine("Cena samochodu: " + price);
    }

Spróbujmy teraz wywołać metodę z obiektu klasy Car:

   static void Main() {
        double tempPrice = 0;
        Car auto = new Car();      
        auto.Price = -120000;
        auto.ViewInformation();    
        Console.ReadLine();        
    }

Kompilator zgłasza nam błąd:

cz2-6

Rys. Błąd zgłoszony przez kompilator

Dzięki użyciu modyfikatora dostępu private mamy możliwość „ukrycia” metody.

Podsumowanie:
Enkapsulacja to ukrywanie elementów klasy bądź struktury, do których użytkownik nie powinien mieć dostępu za pomocą odpowiednich mechanizmów, dzięki którym możemy określić dostępność elementów z poziomu obiektu. Hermetyzację metod w klasie możemy przeprowadzić za pomocą odpowiedniego modyfikatora dostępu. Natomiast dostęp do pola ustawiamy za pomocą odpowiednich publicznych metod lub właściwości, po wcześniejszej zmianie modyfikatora dostępu dla pola na prywatny.
W właściwościach do odczytania wartości danej zmiennej służy akcesor get natomiast do zapisu set.