Auto properties – jak działają?

Automatyczne property są z nami od C# 3. Dzięki nim udało się zaoszczędzić ogromną ilość czasu programistów a co za tym idzie ograniczyć ilość produkowanych błędów. Mimo tego, że codziennie są stosowane przez wszystkich programistów C# co jakiś czas spotykam się z pytaniem jak one działają i skąd się wzięły. W tym artykule postaram się odpowiedzieć na oba te pytania.

Rys historyczny

Jak wszystkim wiadomo C# od samego początku miał być bezpośrednią konkurencją dla Javy. C# wyszedł z propozycją koncepcji property ale najpierw przyjrzyjmy się jak w Javie wyglądał by kod, który pobiera i ustawia wiek osoby:

// Kod Javy przetłumaczony na C#
public class Person
{
    private int _age;

    public int GetPersonAge()
    {
        return _age;
    }

    public void SetPersonAge(int value)
    {
        _age = value;
    }
}

Sporo kodu. 15 Linijek tylko po to, żeby udostępnić możliwość ustawiania jednego pola (Java do tej pory nie ma koncepcji property i trzeba pisać kod jak wyżej).

C# 1

W 2002 roku kiedy C# ujrzał światło dzienne już posiadał koncept property, który wygląda znajomo ale jednak jeszcze mu daleko do postaci którą teraz znamy:

public class Person
{
    private int _age;

    public int Age
    {
        get { return _age; }
        set { value = _age; }
    }
}

// nie można było używać takiej składni przy tworzeniu nowego obiektu:
var person = new Person()
{
    Age = 10
};


// zamiast tego musieliśmy to robić tak:
var person = new Person();
person.Age = 10;

Spore udogodnienie względem poprzedniego kodu. Od początku wszyscy pisali kod w sposób przedstawiony wyżej. Jak się z czasem okazało, większość property nie miało żadnej logiki ani walidacji.

C# 3

Niestety na usprawnienie tego mechanizmu przyszło nam czekać 5 lat. Dopiero z nadejściem trzeciej wersji C# w 2007 roku, Microsoft zaimplementował automatyczne property jakie znamy teraz:

public class Person
{
    public int Age { get; set; }
}

// można już używać takiej składni:
var person = new Person()
{
    Age = 10
};

powyższy kod jest kompilowany do:

public class Person
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Age>k__BackingField;

    public int Age
    {
        [CompilerGenerated]
        get
        {
            return <Age>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Age>k__BackingField = value;
        }
    }
}

Wygląda znajomo? Tak, kod auto property jest kompilowany do get/set znanego z c# 1.

C# 6

W szóstej wersji C# nie było dużych zmian. Dodano tylko możliwość przypisania domyślnej wartości do property:

public class Person
{
	public int Age { get; set; } = 10;
}

Modyfikatory dostępu

Przykładowe modyfikatory dostępu:

// dostępny publicznie ale ustawić można tylko wewnątrz klasy
public int Age { get; private set; } 

// dostępny publicznie ale ustawić można wewnątrz tego samego namespace
public int Age { get; internal set; } 

// dostępny publicznie ale ustawić wartość można tylko przy tworzeniu obietku.
public int Age { get; init; }