2015-08-14 12 views
6

Przechodzę przez książkę Head First C# i nie mogę zrozumieć, dlaczego użyli następującego sposobu, aby utworzyć właściwość. Wydaje się to być niekonsekwentne z konwencją, którą widzę w innych miejscach, także w samej książce.Head First C#: dziwny sposób tworzenia właściwości tylko do odczytu

Rozumiem, że wzorzec dla właściwości tworzących to:

private int myVar; 

    public int MyProperty 
    { 
     get { return myVar; } 
     set { myVar = value; } 
    } 

Na podstawie powyższego wzoru bym napisał mój kod tak:

private decimal cost; 

    public decimal Cost 
    { 
     get 
     { 
      cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
      if (HealthyOption) 
      { 
       cost *= .95M; 
      } 

      return cost; 
     } 

    } 

W książce jest on prezentowany jakby Po:

public decimal Cost 
    { 
     get 
     { 
      decimal totalCost = CalculateCostOfDecorations(); 
      totalCost += (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson)*NumberOfPeople; 

      if (HealthyOption) 
      { 
       totalCost *= .95M; 
      } 
      return totalCost; 
     } 

    } 

Oba kody działają dobrze w programie. Jaka jest najlepsza praktyka tworzenia takich właściwości? Czy dziesiętny totalCost znajduje się wewnątrz obiektu prywatny? Jeśli tak, dlaczego nie jest ona zadeklarowana przed utworzeniem właściwości?

Ponadto, co jest punktem tworząc dwa wiersze kodu:

  decimal totalCost = CalculateCostOfDecorations(); 
      totalCost += (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson)*NumberOfPeople; 

kiedy można osiągnąć dokładnie to samo, pisząc:

cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
+6

nie ma powodu, aby przechowywać 'cost' jako pole podkładu, ponieważ jest każdorazowo przeliczane na getter jest wywoływany. 'TotalCost' jest zmienną lokalną, nie istnieje poza zakresem gettera, jest tymczasowy do przechowywania wyniku obliczeń do momentu, gdy wartość zostanie zwrócona.Użycie "dziesiętnej" z tą samą nazwą zmiennej dwa razy jest błędem składni i spowoduje błąd podczas próby kompilacji. –

+0

Dziękuję za odpowiedź. Również "dziesiętny" użyty dwukrotnie był literówką, dzięki za wskazanie go. – alegz

Odpowiedz

8

Podstawowa różnica między tymi dwoma próbkami jest, jak już zauważyliśmy, że jeden ma pole podkładową (czego oddanie decimal cost poza definicją własności robi), a drugi nie.

Zmienna totalCost w drugiej próbce nie jest wcale polem (private lub innym), jest po prostu zmienną lokalną dla metody get.

Obie są w porządku, ale jeśli nie korzystasz z niczego, nie jest to konieczne. Co do twojego drugiego pytania, nie mam pojęcia, dlaczego tak właśnie postąpili w ten sposób, poza tym, że uproszczenie deklaracji zmiennych.

Na marginesie, zarówno próbki są nieco poza standardową praktyką C#, ponieważ jest to bardzo dużo logiki dla gettera właściwości.

3

jest dziesiętny totalCost wewnątrz własność prywatna? Jeśli tak, to dlaczego nie został on zadeklarowany przed utworzeniem właściwości?

Jest on tworzony wewnątrz property, aby ograniczyć jego zakres. Jeśli zadeklarujesz wartość totalCost powyżej property, będzie ona dostępna w całej wersji class.

Ponadto, co jest punktem tworząc dwa wiersze kodu:

zwykle, tylko dla czytelności. Jedna wkładka jest świetna, dopóki nie musisz przewijać, aby zobaczyć ją w całości.

0

Tak, właściwości oparte na obliczeniach nie wymagają w ogóle pola prywatnego do przechowywania wartości (chyba że chcesz zapisać wartość w pamięci podręcznej, aby uniknąć ponownego obliczania po otrzymaniu). w rzeczywistości jeszcze lepiej (przynajmniej terser i łatwiejsze do naśladowania) sposobem jest zrobić to bez zmiennych lokalnych w ogóle:

public decimal Cost 
{ 
    get 
    { 
     return (CalculateCostOfDecorations() + 
       (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) 
       * NumberOfPeople) * HealthyOption? .95m: 1m; 
    } 
} 
1

Zmienna totalCost nie private jest to zmienna lokalna wewnątrz getter. Zmienna nie istnieje poza tą metodą, więc zajmuje tylko pamięć podczas uruchamiania. Twoje pole private cost pozostanie w pamięci tak długo, jak długo będzie zajmować instancja klasy. Zmienna jest używana tylko wewnątrz gettera, więc powinna być lokalna w geterze, jak pokazuje książka. Nie ma powodu, aby było to pole klasy.

Punktem tworzenia dwóch linii jest dopasowanie do pojedynczej linii na stronie. Kod jest dokładnie taki sam; jest inaczej sformatowany.

0

Należy właściwie użyć Get metodę tylko zwróci wartość zmiennej prywatnej, jako że jest to dobra praktykado naśladowania. Ułatwi ci to zachowanie innych funkcji, które mogą używać zmiennej prywatnej "na wszelki wypadek".

Zawsze używaj "setterów" do zmiany wartości zmiennej, "getters", aby po prostu zwrócić ją bez żadnych zmian.

+0

Czy możesz podać przykład? – alegz

2

Jak wspomniano przez innych, ani z nich jest naprawdę idiomatycznych C#, jednak mający pole poparcie dla mogłoby to prowadzić do błędów w dalszej części kodu, np:

private decimal cost; 

public decimal Cost 
{ 
    get 
    { 
     cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
     if (HealthyOption) 
     { 
      cost *= .95M; 
     } 

     return cost; 
    } 

} 

public decimal CalculateDiscountedCost() { 
    return cost * 0.75m; //Note the deliberate mistake? 
} 

przez (prawdopodobnie przypadkowo) uzyskiwania dostępu do zmienna backingowa w kolejnej metodzie, a nie na własność, z której można łatwo stworzyć trudny do utrzymania kod. W takim przypadku zdyskontowany koszt może być prawidłowy po wywołaniu, ale będzie zależał od publicznej właściwości Cost uzyskiwanej przed wywołaniem metody CalculateDiscountedCost w celu ustawienia zmiennej zabezpieczającej.

Ponieważ zmienna jest zasadniczo niepotrzebna, lepiej byłoby bez niej obejść się.

+0

Tak więc, tworząc zmienną lokalną do metody get, jak przedstawiono w książce, zamiast zmiennej pomocniczej, uniknięto by tego rodzaju błędu. Czy dobrze rozumiem? – alegz

+1

Zgadza się. Chodzi raczej o to, jak można konserwować kod, a nie o prawdziwą różnicę w funkcjonalności. – Paddy

4

Oba sposoby "praca". Jeśli pytasz, która droga jest najlepsza, powiedziałbym nie.

Ponieważ Cost nie jest tak naprawdę polem lub właściwością (jest to coś, co jest obliczane i nie może być ustawione przez osobę dzwoniącą), byłoby bardziej idiomatyczne do wdrożenia jako metoda zwracająca wartość. Żadna zmienna składowa nie powinna być potrzebna.

public decimal GetCost() 
{ 
    var cost = CalculateCostOfDecorations() + (CalculateCostOfBeveragesPerPerson() + CostOfFoodPerPerson) * NumberOfPeople; 
    if (HealthyOption) 
    { 
     cost *= .95M; 
    } 
    return cost; 
} 
+0

Dzięki! Chciałem zapytać, czy w tym przypadku lepiej byłoby stworzyć metodę zamiast własności, ale to sprawiłoby, że pytanie byłoby jeszcze dłuższe. – alegz

+0

Zdecydowanie napisałbym tutaj metodę - zwłaszcza, że ​​wywołuje metodę ('CalculateCostOfDecorations()'). Właściwości powinny być bardzo lekkie i nie powinny mieć skutków ubocznych. –

0

Sugerowałbym, że w takich przypadkach trzeba (gdzie pobrać i ustawić po prostu zwrócić lub ustawić wartość zmiennej pojedynczego podkładu), że używasz „Automatic” właściwości, takie jak to:

public int MyProperty { get; set; } 

I, być może, nie chcą użytkownicy zewnętrzni klasy mieć dostęp do tej seter:

public int MyProperty { get; private set; } 
Powiązane problemy