Chodzę teraz na zajęcia z C # i próbuję znaleźć najlepszy sposób robienia rzeczy. Pochodzę z języka Java, więc znam tylko najlepsze praktyki dotyczące języka Java; Jestem nowicjuszem C #!
W Javie, jeśli mam prywatną własność, robię to;
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
W języku C # widzę, że jest na to wiele sposobów.
Mogę to zrobić jak Java:
private string name;
public void setName(string name) {
this.name = name;
}
public string getName() {
return this.name;
}
Albo mogę to zrobić w ten sposób:
private string name;
public string Name {
get { return name; }
set { name = value; }
}
Lub:
public string Name { get; set; }
Którego należy użyć i jakie są zastrzeżenia lub subtelności związane z każdym podejściem? Tworząc zajęcia kieruję się ogólnymi dobrymi praktykami, które znam z języka Java (zwłaszcza czytając efektywną Javę). Na przykład opowiadam się za niezmiennością (zapewnianie ustawiaczy tylko wtedy, gdy jest to konieczne). Jestem po prostu ciekawy, jak te praktyki pasują do różnych sposobów dostarczania metod ustawiających i pobierających w języku C #; zasadniczo, jak przełożyłbym najlepsze praktyki ze świata Java na C #?
EDYTOWAĆ
Publikowałem to jako komentarz do odpowiedzi Jona Skeeta, ale potem zrobiło się to długo:
A co z nietrywialną właściwością (tj., Być może z dużym przetwarzaniem i walidacją)? Czy nadal mogę go ujawnić za pośrednictwem własności publicznej, ale z logiką zawartą w get
i set
? Dlaczego miałbym / powinienem robić to ponad mając dedykowane metody ustawiające i pobierające (z powiązaną logiką przetwarzania i walidacji).
źródło
public int Y { get; } = y;
).Jeśli potrzebujesz tylko zmiennej do przechowywania niektórych danych:
public string Name { get; set; }
Chcesz, aby był on tylko do odczytu?
public string Name { get; private set; }
Albo jeszcze lepiej ...
private readonly string _name; ... public string Name { get { return _name; } }
Chcesz sprawdzić wartość przed przypisaniem właściwości?
public string Name { get { return m_name; } set { if (value == null) throw new ArgumentNullException("value"); m_name = value; } }
Ogólnie rzecz biorąc, GetXyz () i SetXyz () są używane tylko w niektórych przypadkach i po prostu musisz użyć swojego jelita, gdy czujesz się dobrze. Ogólnie rzecz biorąc, spodziewam się, że większość właściwości get / set nie będzie zawierała dużej ilości logiki i będzie miała bardzo mało, jeśli w ogóle, nieoczekiwanych skutków ubocznych. Jeśli odczytanie wartości właściwości wymaga wywołania usługi lub uzyskania danych wejściowych od użytkownika w celu zbudowania obiektu, o który żądam, to zawinąłbym go w metodę i nazwałbym to czymś podobnym
BuildXyz()
, a nieGetXyz()
.źródło
myList.Add()
, na przykład (dopóki obiekt jest narażony na zmianę, jest zmienny).Min
/Max
. Chcesz to zapewnićMax > Min
? PosiadanieSetRange(Min, Max)
makijaż może sens, ale to jak masz zamiar czytać te wartości z powrotem? Właściwości Min / Max tylko do odczytu? Zgłaszanie wyjątków dla nieprawidłowych danych wejściowych wydaje się najczystszym sposobem rozwiązania tego problemu.Użyj właściwości w języku C #, a nie metod pobierania / ustawiania. Są tam dla Twojej wygody i jest to idiomatyczne.
Jeśli chodzi o twoje dwa przykłady w C #, jeden jest po prostu cukrem syntaktycznym dla drugiego. Użyj właściwości auto, jeśli potrzebujesz tylko prostego opakowania wokół zmiennej instancji, użyj pełnej wersji, gdy potrzebujesz dodać logikę do metody pobierającej i / lub ustawiającej.
źródło
W języku C # preferują właściwości do ujawniania pól prywatnych do pobierania i / lub ustawiania. Ta forma, o której wspomniałeś, to autopertyza, w której get and set automatycznie generuje ukryte pole bazowe przestawne.
Preferuję właściwości automatyczne, jeśli to możliwe, ale nigdy nie powinieneś robić pary metod set / get w C #.
źródło
public string Name { get; set; }
Jest to po prostu właściwość zaimplementowana automatycznie i jest technicznie taka sama jak normalna właściwość. Podczas kompilacji zostanie utworzone pole zapasowe.
Wszystkie właściwości są ostatecznie konwertowane na funkcje, więc ostatecznie skompilowana implementacja jest taka sama, jak w Javie.
Użyj właściwości implementowanych automatycznie, gdy nie musisz wykonywać określonych operacji na polu zapasowym. W przeciwnym razie użyj zwykłej właściwości. Użyj funkcji get i set, gdy operacja ma skutki uboczne lub jest kosztowna obliczeniowo, w przeciwnym razie użyj właściwości.
źródło
Niezależnie od tego, który sposób wybierzesz w C #, efekt końcowy jest taki sam. Otrzymasz zmienną backinng z oddzielnymi metodami pobierającymi i ustawiającymi. Korzystając z właściwości, postępujesz zgodnie z najlepszymi praktykami, więc jest to kwestia tego, jak dokładny chcesz uzyskać.
Osobiście wybrałbym właściwości automatyczne, ostatnią wersję:
public string Name { get; set; }
ponieważ zajmują najmniej miejsca. I zawsze możesz je rozszerzyć w przyszłości, jeśli potrzebujesz czegoś takiego jak walidacja.źródło
Jeśli to możliwe, wolę publiczne,
string Name { get; set; }
ponieważ jest zwięzłe i łatwe do odczytania. Jednak może się zdarzyć, że będzie to konieczneprivate string name; public string Name { get { return name; } set { name = value; } }
źródło
C # preferowanym sposobem jest przez właściwości aniżeli
getX()
isetX()
Metody. Należy również zauważyć, że C # nie wymaga, aby właściwości miały zarówno get, jak i set - możesz mieć właściwości tylko do pobierania i właściwości tylko do zestawu.public boolean MyProperty { get { return something; } } public boolean MyProperty { set { this.something = value; } }
źródło
Najpierw spróbuję wyjaśnić, co napisałeś:
// private member -- not a property private string name; /// public method -- not a property public void setName(string name) { this.name = name; } /// public method -- not a property public string getName() { return this.name; } // yes it is property structure before .Net 3.0 private string name; public string Name { get { return name; } set { name = value; } }
Ta struktura jest również używana w dzisiejszych czasach, ale jest najbardziej odpowiednia, jeśli chcesz wykonać dodatkowe funkcje, na przykład gdy ustawiono wartość, możesz ją przeanalizować, aby ją wykorzystać i zapisać w prywatnym elemencie w celu zmiany użytku wewnętrznego.
Dzięki .NET Framework 3.0
// this style is introduced, which is more common, and suppose to be best public string Name { get; set; } //You can more customize it public string Name { get; private set; // means value could be set internally, and accessed through out }
Życzę powodzenia w C #
źródło
Jak wspomniano, wszystkie te podejścia prowadzą do tego samego wyniku. Najważniejsze, żeby wybrać konwencję i się jej trzymać. Wolę używać dwóch ostatnich przykładów właściwości.
źródło
podobnie jak większość odpowiedzi tutaj, użyj właściwości automatycznych. Intuicyjny, mniej linijek kodu i bardziej przejrzysty. Jeśli powinieneś serializować swoją klasę, oznacz klasę
[Serializable]
/[DataConract]
atrybutem. A jeśli używasz,[DataContract]
oznacz członka za pomocą[DataMember(Name="aMoreFriendlyName")] public string Name { get; set; }
Ustawiacz prywatny lub publiczny zależy od twoich preferencji.
Należy również zauważyć, że właściwości automatyczne wymagają zarówno metod pobierających, jak i ustawiających (publicznych lub prywatnych).
/*this is invalid*/ public string Name { get; /* setter omitted to prove the point*/ }
Alternatywnie, jeśli chcesz tylko pobrać / ustawić, samodzielnie utwórz pole zapasowe
źródło
W przypadku właściwości istnieje jedno zastrzeżenie, o którym jeszcze nie wspomniano: w przypadku właściwości nie można mieć żadnej parametryzacji metod pobierających ani ustawiających.
Na przykład wyobraź sobie, że chcesz pobrać elementy listy i jednocześnie chcesz zastosować filtr. Za pomocą metody get możesz napisać coś takiego:
obj.getItems(filter);
W przeciwieństwie do właściwości, musisz najpierw zwrócić wszystkie elementy
obj.items
a następnie zastosuj filtr w następnym kroku lub musisz dodać dedykowane właściwości, które eksponują elementy przefiltrowane według różnych kryteriów, co wkrótce nadyma Twój interfejs API:
obj.itemsFilteredByX obj.itemsFilteredByY
To, co czasami może być uciążliwe, to sytuacja, w której zaczynasz od właściwości, np.
obj.items
A później odkrywasz, że parametryzacja gettera lub settera jest potrzebna lub może ułatwić pracę użytkownikowi klasowego API. Będziesz teraz musiał albo przepisać swoje API i zmodyfikować wszystkie te miejsca w kodzie, które mają dostęp do tej właściwości, albo znaleźć alternatywne rozwiązanie. W przeciwieństwie do metody get, np.obj.getItems()
Możesz po prostu rozszerzyć sygnaturę swojej metody, aby zaakceptowała opcjonalny obiekt "konfiguracyjny", np.obj.getItems(options)
Bez konieczności przepisywania wszystkich miejsc, które wywołują twoją metodę.Biorąc to pod uwagę, (automatycznie implementowane) właściwości w C # są nadal bardzo przydatnymi skrótami (z różnych powodów wymienionych tutaj), ponieważ przez większość czasu parametryzacja może nie być potrzebna - ale to zastrzeżenie pozostaje.
źródło