2008-11-06 6 views
84

Chciałbym usłyszeć, jaka jest motywacja większości zapieczętowanych klas w środowisku .Net. Jaka jest korzyść z uszczelniania klasy? Nie potrafię pojąć, w jaki sposób nie pozwolić, by dziedziczenie mogło być użyteczne i najprawdopodobniej nie jedynym, który walczyłby z tymi klasami.Po co pieczętować klasę?

A więc, dlaczego ramy zostały zaprojektowane w ten sposób i czy nie byłoby to przełomową zmianą, aby wszystko pozbyć się? Musi być inny powód, ale po prostu bycie złym?

+2

Powiedziałbym, że [nie * kiedykolwiek * pieczęć klasy, chyba że wiesz * będziesz mieć problemy z obsługą klientów.] (Http://programmers.stackexchange.com/a/210481/4261) – cregox

+1

Możliwy duplikat [Dlaczego istnieje opcja dla klasy w OOP być oznaczone, aby nigdy nie dziedziczyć od przodków?] (Http://stackoverflow.com/questions/12588158/why-there-is-an-option-for-a Klasyka w oznakowaniu, aby nigdy nie odziedziczyć-z-ancest/21116956) – Doval

Odpowiedz

37
  • Niekiedy zajęcia są zbyt cenne i nie są przeznaczone do odziedziczenia.
  • Środowisko wykonawcze/Odbicie może tworzyć założenia dziedziczenia dotyczące klas zapieczętowanych podczas wyszukiwania typów. Doskonałym przykładem tego jest - Zaleca się, aby Atrybuty były zapieczętowane w celu sprawdzenia szybkości działania. type.GetCustomAttributes (typeof (MyAttribute)) będzie działał znacznie szybciej, jeśli MojaAttribute zostanie zapieczętowana.

Artykuł MSDN na ten temat to Limiting Extensibility by Sealing Classes.

+3

Cieszę się, że teraz wyraźnie mówią "używaj ostrożnie" teraz ... życzą sobie, aby ćwiczyli to, co głoszą. – mmiika

+11

To wygląda na złą radę :( –

+0

Nie mam zdania, to nie moja rada, C# daje ci kontrolę - co jest w porządku Nigdy nie wpadłem na problem z zapieczętowanymi klasami (tj. Gdybym to zrobił, po prostu zapakowałbym zapieczętowaną klasę: – CVertex

3

Znalazłem to zdanie w dokumentacji msdn: "Zapieczętowane klasy są używane przede wszystkim do zapobiegania wyprowadzaniu, ponieważ nigdy nie mogą być używane jako klasa podstawowa, niektóre optymalizacje w czasie pracy mogą sprawić, że połączenie z zapieczętowanymi członkami klasy będzie nieco szybsze."

ja nie wiem, czy wydajność jest jedyną zaletą zamkniętych klasach i osobiście też chcieliby wiedzieć jakiekolwiek inne powody ...

+3

Byłoby interesujące zobaczyć, jakiego rodzaju korzyści z wydajności mówią o ... – mmiika

89

Ćwiczenia powinny albo być zaprojektowane dla dziedziczenia lub zakazać go. Jest to koszt projektowania do dziedziczenia:

  • To może zmusić implementacji (trzeba deklarować, jakie metody są zamiar zadzwonić których inne metody, w przypadku, gdy użytkownik zastępuje jeden, ale nie inne)
  • ujawnia implementacji raczej niż tylko efekty
  • oznacza, że ​​trzeba myśleć o więcej możliwości przy projektowaniu
  • rzeczy takie jak Equals są trudne do zaprojektowania w drzewie dziedziczenia
  • wymaga więcej dokumentacji
  • niezmienna typu, który jest podklasy może być zmienny (ICK)

Pozycja 17 z Effective Java przechodzi w więcej szczegółów na ten temat - niezależnie od faktu, że jest on napisany w kontekście Java, rada odnosi się do .NET także.

Osobiście chciałbym, aby klasy były domyślnie zaplombowane w .NET.

+23

Hmm .. jeśli rozszerzysz klasę, czy nie jest to twój problem, jeśli ją złamiesz? – mmiika

+20

Co się stanie, jeśli zmiana implementacji, nad którą nie masz kontroli w klasie bazowej, powoduje podział? Czyja to wina? Dziedziczenie po prostu wprowadza kruchość. Kompozycja sprzyjająca dziedziczeniu promuje odporność, IMO. –

+2

Prawda. Ok, ma sens, jeśli zapewnisz jakieś środki (być może osobny interfejs), aby napisać własną implementację dla celów testowalności. Właśnie spędziłem jedną godzinę na pisanie dekoratorów wokół tych zajęć :) – mmiika

2

Wydajność jest ważnym czynnikiem, na przykład, klasa łańcuchowa w java jest ostateczna (< - zapieczętowana), a powodem tego jest tylko wydajność. myślę kolejnym ważnym punktem jest to, aby uniknąć kruche klasy bazowej problem opisany szczegółowo tutaj: http://blogs.msdn.com/ericlippert/archive/2004/01/07/virtual-methods-and-brittle-base-classes.aspx

Jeśli stworzenie ram ważne jest dla projektów konserwacji starszych i uaktualnić ramy aby uniknąć klasy problemu kruche podstawy

+0

Powód, dla którego String w java jest ostateczny, nie jest wydajnością, jest zabezpieczeniem. – CesarB

+0

@ CesarB: Tak, ale także, String nie jest normalną klasą Java. Jest to jedyna (jak sądzę) klasa w Javie, która obsługuje przeciążanie operatorów (więcej informacji można znaleźć w [tutaj] (http://stackoverflow.com/a/194889), sekcja: "Nawet C i Java mają przeciążony operator (na stałe) "), co nie jest możliwe w normalnej klasie. Z tego powodu klasa 'String' może nie być nawet możliwa do podklasy, nawet jeśli nie jest ostateczna. – wchargin

0

Uszczelnienie pozwala uzyskać niewielkie przyrosty wydajności. Jest to mniej prawdziwe w świecie JIT i leniwej pesymizacji niż w świecie C++, ale od tego czasu.NET nie jest tak dobry jak pesymizacja, ponieważ kompilatory java są głównie z powodu różnych filozofii projektowania, które są nadal przydatne. Mówi kompilatorowi, że może bezpośrednio wywoływać dowolne metody wirtualne, zamiast wywoływać je pośrednio przez vtable.

Jest również ważna, gdy chce się "zamkniętego świata", np. Porównywania równości. Normalnie raz zdefiniowałem wirtualną metodę, jestem prawie w stanie zdefiniować pojęcie porównania równości, które naprawdę implementuje ideę. Z drugiej strony, mogę być w stanie zdefiniować go dla konkretnej podklasy klasy za pomocą metody wirtualnej. Zamknięcie tej klasy zapewnia, że ​​równość naprawdę istnieje.

1

Zapieczętowane służy do zapobiegania "problemowi klasy łamliwej klasy". Znalazłem w MSDN good article, który to wyjaśnia.

0

Zamknięcie klasy ułatwia zarządzanie zasobami jednorazowymi.

4

Wydaje się, że official Microsoft guidelines on sealing ewoluowały od tego pytano ~ 9 lat temu i przenieśli się z filozofią opt-in (domyślnie) uszczelnienia do opt-out (nie uszczelnić domyślnie):

X NIE GOTOWAĆ klas pieczęci bez uzasadnionego powodu.

Zamknięcie klasy, ponieważ nie można myśleć o scenariuszu rozszerzalności , nie jest dobrym powodem. Korzystający z frameworków dziedziczą z klas na różne nieoczywiste powody, na przykład dodając wygody członków. Zapoznaj się z klasami niezamkniętymi dla przykładów nieoczywistych powodów, dla których użytkownicy chcą dziedziczyć po typie.

Powody do uszczelniania klasy są następujące:

  • Klasa jest klasą statyczną. Zobacz Statyczny projekt klasy.
  • Klasa przechowuje sekrety wrażliwe na ochronę w odziedziczonych chronionych elementach.
  • Klasa dziedziczy wiele wirtualnych elementów, a koszt ich uszczelnienia pojedynczo przewyższałby zalety pozostawienia klasy niezajętej klasy .
  • Klasa jest atrybutem wymagającym bardzo szybkiego wyszukiwania w czasie wykonywania. Zapieczętowane atrybuty mają nieco wyższy poziom wydajności niż te nieobsługiwane. Zobacz Atrybuty.

X NIE NALEŻY zadeklarować chronionych lub wirtualnych członków na zapieczętowanych typach.

Z definicji typy zamknięte nie mogą być dziedziczone. Oznacza to, że chronione elementy na zamkniętych typach nie mogą być wywoływane, a wirtualne metody w zaplombowanych typach nie mogą zostać nadpisane.

✓ UWAŻAJ elementów uszczelniających, które można przesłonić. Problemy, które mogą wyniknąć z wprowadzenia wirtualnych członków (omówione w Virtual Member) , dotyczą również przesłonięć, choć w nieco mniejszym stopniu. Zamknięcie obejścia chroni przed tymi problemami, zaczynając od tego punktu w hierarchii dziedziczenia.

Rzeczywiście, jeśli search the ASP.Net Core codebase znajdziesz tylko około 30 wystąpień sealed class, z których większość atrybutów i klas testowych.

Uważam, że niezmienna konserwacja to dobry argument na korzyść uszczelnienia.

0

Aby ustalić, czy do uszczelniania klasy, metody lub właściwości, należy na ogół pod uwagę następujące dwa punkty:

• Potencjalne korzyści wynikające że zajęcia mogą zyskać poprzez zdolność do dostosowania swojej klasy.

• Potencjał czerpiący z zajęć może modyfikować klasy w taki sposób, aby nie działały poprawnie lub zgodnie z oczekiwaniami.