Różnica między właściwością a polem w języku C # 3.0+

140

Zdaję sobie sprawę, że wydaje się być duplikatem Jaka jest różnica między polem a właściwością w C #? ale moje pytanie ma niewielką różnicę (z mojego punktu widzenia):

Kiedy już to wiem

  • Nie będę używał mojej klasy z „technikami, które działają tylko na właściwościach” i
  • Nie będę używał kodu walidacyjnego w getter / setter.

Czy jest jakaś różnica (poza stylem / przyszłym rozwojem), jak jakiś rodzaj kontroli w ustawianiu właściwości?

Czy jest jakaś dodatkowa różnica między:

public string MyString { get; set; }

i

public string myString;

(Mam świadomość, że pierwsza wersja wymaga C # 3.0 lub nowszego i że kompilator tworzy pola prywatne).

p4bl0
źródło
możliwy duplikat automatycznie wdrażanych
metod pobierających

Odpowiedzi:

117

Kapsułkowanie.

W drugim przypadku właśnie zdefiniowałeś zmienną, w pierwszym, wokół zmiennej znajduje się funkcja pobierająca / ustawiająca. Jeśli więc zdecydujesz, że chcesz zweryfikować zmienną w późniejszym terminie - będzie to o wiele łatwiejsze.

Poza tym w Intellisense wyglądają inaczej :)

Edycja: zaktualizowane pytanie dla OP - jeśli chcesz zignorować inne sugestie tutaj, innym powodem jest to, że po prostu nie jest to dobry projekt OO. A jeśli nie masz dobrego powodu, aby to robić, zawsze wybieraj właściwość zamiast publicznej zmiennej / pola.

Mark Ingram
źródło
9
Dlaczego będzie łatwiej? Co powstrzymuje mnie przed przekształceniem pola w właściwość i dodaniem prywatnego pola zapasowego? Jak to wpływa na wywołanie kodu?
Serge Wautier
30
@Serge - wpływa na już skompilowany kod. Na przykład, jeśli tworzysz bibliotekę używaną przez kilka aplikacji, zmiana pola na właściwość w tej bibliotece wymagałaby ponownej kompilacji każdej aplikacji. Gdyby to była właściwość, można by ją zaktualizować bez obaw.
Dustin Campbell,
Całkowicie się z tobą zgadzam, używam zawsze właściwości. Byłem po prostu ciekawy możliwej różnicy
p4bl0
24
Jeśli konsumujący kod jest zawsze rekompilowany w tym samym czasie co klasa, której dotyczy problem (więc wszystko, co prywatne lub wewnętrzne bez widocznych elementów wewnętrznych, jest w 100% bezpieczne), to uczynienie tego pola jest całkowicie w porządku
ShuggyCoUk
1
wow Shuggy Twój komentarz jest dokładnie tą odpowiedzią, której szukałem!
p4bl0
160

Pola i właściwości wyglądają tak samo, ale tak nie jest. Właściwości są metodami i jako takie istnieją pewne rzeczy, które nie są obsługiwane w przypadku właściwości oraz pewne rzeczy, które mogą się zdarzyć w przypadku właściwości, ale nigdy w przypadku pól.

Oto lista różnic:

  • Pola mogą być używane jako dane wejściowe dla out/refargumentów. Właściwości nie mogą.
  • Pole zawsze daje ten sam wynik, gdy jest wywoływane wiele razy (jeśli pominiemy problemy z wieloma wątkami). Właściwość taka DateTime.Nownie zawsze jest sobie równa.
  • Właściwości mogą generować wyjątki - pola nigdy tego nie zrobią.
  • Właściwości mogą powodować skutki uboczne lub zajmować naprawdę dużo czasu. Pola nie mają skutków ubocznych i zawsze będą tak szybkie, jak można się spodziewać dla danego typu.
  • Właściwości obsługują różną dostępność dla pobierających / ustawiających wartości - pola nie obsługują (ale można tworzyć pola readonly)
  • Przy użyciu odbicia właściwości i pola są traktowane jako inny MemberTypestak, że znajdują się w różny sposób ( GetFieldsvs GetPropertiesna przykład)
  • Kompilator JIT może traktować dostęp do właściwości inaczej niż dostęp do pola. Może jednak skompilować się do identycznego kodu natywnego, ale istnieją różnice.
Brian Rasmussen
źródło
11
Należy jednak pamiętać, że kilka z tych punktów nie powinno być różnic, jeśli stosowane są dobre praktyki. Oznacza to, że właściwości nigdy nie powinny wywoływać skutków ubocznych, ani też nie powinny zajmować dużo czasu.
Noldorin,
15
@Noldorin: Zgadzam się, ale niestety powinno być tutaj słowem kluczowym. W przypadku pól takie zachowanie jest gwarantowane. Nie mówię, że powinieneś używać pól, ale ważne jest, aby być świadomym różnic semantycznych.
Brian Rasmussen
4
Tak, w porządku. Początkujący programiści często nie mają pojęcia o tych rzeczach, niestety ...
Noldorin
2
Ponadto pola mogą mieć inicjator pola, podczas gdy właściwości muszą być inicjowane w konstruktorze.
Dio F
3
Czuję, że ta odpowiedź jest lepsza niż akceptowana odpowiedź. Zaczynam myśleć, że „akceptowalnym” sposobem preferowania zawsze właściwości nad polami jest złe myślenie. Jeśli potrzebujesz tylko danych, użyj pola. Jeśli chcesz zastosować funkcje do danych, użyj metody. Ponieważ właściwości mogą mieć skutki uboczne, których nie jesteś świadomy (zwłaszcza jeśli nie zaprojektowałeś biblioteki i masz niewielką dokumentację), w większości przypadków wydają mi się sprzeczne z intuicją.
David Peterson,
41

Kilka szybkich, oczywistych różnic

  1. Właściwość może mieć słowa kluczowe akcesorów.

    public string MyString { get; private set; }
  2. Właściwość można zastąpić w potomkach.

    public virtual string MyString { get; protected set; }
Dustin Campbell
źródło
1
mmh .. nr 2 jest interesujący .. nie pomyślałem o tym
p4bl0
14

Podstawowa różnica polega na tym, że pole to pozycja w pamięci, w której przechowywane są dane określonego typu. Właściwość reprezentuje jedną lub dwie jednostki kodu, które są wykonywane w celu pobrania lub ustawienia wartości określonego typu. Użycie tych metod dostępu jest ukryte składniowo przez użycie elementu członkowskiego, który wydaje się zachowywać jak pole (w tym sensie, że może pojawić się po obu stronach operacji przypisania).

AnthonyWJones
źródło
11

Akcesory to coś więcej niż pola. Inni już wskazali kilka ważnych różnic, a ja dodam jeszcze jedną.

Właściwości biorą udział w klasach interfejsów. Na przykład:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Ten interfejs można spełnić na kilka sposobów. Na przykład:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

W tej implementacji chronimy zarówno Personklasę przed wejściem w niepoprawny stan, jak i obiekt wywołujący przed uzyskaniem wartości null z nieprzypisanej właściwości.

Ale możemy jeszcze bardziej rozwinąć projekt. Na przykład interfejs może nie radzić sobie z ustawiaczem. Można powiedzieć, że konsumenci IPersoninterfejsu są zainteresowani tylko uzyskaniem własności, a nie jej ustawieniem:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Poprzednia implementacja Personklasy spełnia wymagania tego interfejsu. Fakt, że pozwala dzwoniącemu również ustawić właściwości, jest bez znaczenia z punktu widzenia konsumentów (konsumujących IPerson). Dodatkową funkcjonalność konkretnej implementacji bierze pod uwagę np. Budowniczy:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

W tym kodzie konsument nie wie o ustawieniach właściwości - wiedza o tym nie jest jego interesem. Konsument potrzebuje tylko getterów, a dostaje gettery z interfejsu, czyli z umowy.

Inną całkowicie poprawną implementacją IPersonbyłaby niezmienna klasa osób i odpowiednia fabryka osób:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

W tym przykładowym kodzie konsument po raz kolejny nie ma wiedzy o wypełnianiu właściwości. Konsument zajmuje się tylko pobieraniem i konkretną implementacją (oraz logiką biznesową stojącą za tym, jak testowanie, jeśli nazwa jest pusta) jest pozostawiona wyspecjalizowanym klasom - budowniczym i fabrykom. Wszystkie te operacje są całkowicie niemożliwe w przypadku pól.

Zoran Horvat
źródło
7

Pierwszy:

public string MyString {get; set; }

jest własnością; druga ( public string MyString) oznacza pole.

Różnica polega na tym, że niektóre techniki (wiązania danych ASP.NET dla instancji) działają tylko na właściwościach, a nie na polach. To samo dotyczy serializacji XML: tylko właściwości są serializowane, pola nie są serializowane.

Frederik Gheysels
źródło
8
Źle. Serializacja XML CZY serializuje pola publiczne.
Serge Wautier
2
Może. Ale kiedy tworzysz źródło danych obiektu z klasy, możesz używać tylko właściwości, a nie pól. (Chyba że zrobiłem coś złego: P)
Svish
Dobrze jest do DRY;) ale piszę jeszcze raz, lubię silną rolę własności w języku C #. Jest znacznie lepiej zaimplementowany niż w Javie (konsekwentnie od początku) Wiele, być może wszystkie rozwiązania .net działają tylko na właściwościach. WPF, ASPX i więcej.
Jacek Cz
3

Właściwości i pola mogą w wielu przypadkach wydawać się podobne, ale tak nie jest. Istnieją ograniczenia dotyczące właściwości, które nie istnieją dla pól i odwrotnie.

Jak wspominali inni. Możesz ustawić właściwość tylko do odczytu lub tylko do zapisu, ustawiając jej metodę dostępu jako prywatną. Nie możesz tego zrobić z polem. Właściwości mogą być również wirtualne, podczas gdy pola nie.

Pomyśl o właściwościach jak o cukrze syntaktycznym dla funkcji getXXX () / setXXX (). W ten sposób są one realizowane za kulisami.

Erik Funkenbusch
źródło
1

Istnieje jeszcze jedna ważna różnica między polami a właściwościami.

W przypadku korzystania z WPF można powiązać tylko właściwości publiczne. Wiązanie z polem publicznym nie będzie działać. Dzieje się tak nawet wtedy, gdy nie wdrażasz INotifyPropertyChanged(chociaż zawsze powinieneś).

BradleyDotNET
źródło
Dobrze jest do DRY;) ale piszę jeszcze raz, lubię silną rolę własności w języku C #. Jest znacznie lepiej zaimplementowany niż w Javie (konsekwentnie od początku) Wiele, być może wszystkie rozwiązania .net działają tylko na właściwościach. WPF, ASPX i więcej.
Jacek Cz
1

Wśród innych odpowiedzi i przykładów myślę, że ten przykład jest przydatny w niektórych sytuacjach.

Na przykład powiedzmy, że masz polubienie:OnChange property

public Action OnChange { get; set; }

Jeśli chcesz używać delegatów, musisz to zmienić OnChangew fieldten sposób:

public event Action OnChange = delegate {};

W takiej sytuacji chronimy nasze pole przed niechcianym dostępem lub modyfikacją.

maytham-ɯɐɥʇʎɐɯ
źródło
0

Należy zawsze używać właściwości zamiast pól dla dowolnych pól publicznych. Dzięki temu Twoja biblioteka będzie miała możliwość implementacji enkapsulacji dla dowolnego pola, jeśli będzie to wymagane w przyszłości, bez łamania istniejących kodów. Jeśli zastąpisz pola właściwościami w istniejących bibliotekach, wówczas wszystkie moduły zależne korzystające z biblioteki również muszą zostać odbudowane.

user1849310
źródło
„zawsze” to mało trudne słowo. W C # (lepszym niż w Javie) właściwość ma mocną pozycję, jest (chyba bez wyjątku) główną / metodą "wiązania" w ASP, WPF i innych. Ale mimo wszystko mogę sobie wyobrazić, że projektowanie z polem, w którym nie ma własności, ma sens (czasami)
Jacek Cz