2013-08-02 13 views
6

Zastanawiam się nad tym, ponieważ muszę dziedziczyć po StringBuilder, aby zrealizować zdarzenie TextChanged. Zawsze mogłem utworzyć opakowanie zawierające private StringBuilder i niejawne/jawne konwersje, ale nie wydaje się to właściwym rozwiązaniem.Dlaczego klasa StringBuilder jest zamknięta?

Na szczęście mogę dziedziczyć obiekt, który pisze do StringBuilder, więc nie jest to dla mnie problemem, ale wciąż jestem ciekawy, dlaczego ta klasa jest zapieczętowana.

+2

Dlaczego trzeba obsługiwać zdarzenie "StringBuilder" TextChanged? To ty dodajesz do niego tekst. Zakładam, że względy wydajności przeważają nad jego rozszerzeniem. –

+0

@Tim Co jeśli jest to 'StringWriter' lub jakaś natywna funkcja jak' SendMessage'? Ponadto lepiej jest pracować z wydarzeniami niż napisać kod typu 'void WriteToBuilder (StringBuilder sb, napis tekstowy)'. – KappaG3

+2

["Projekt i dokument do dziedziczenia lub zakazaj go"] (http://martinfowler.com/bliki/DesignedInheritance.html) – dasblinkenlight

Odpowiedz

12

Odpowiedź jest nieco trudna. Odwrócona odpowiedź ma problem, StringBuilder nie ma żadnych wirtualnych metod. Więc nic nie można zrobić, aby przerwać klasy lub robi coś "extra" niebezpieczne.

Myślę, że prawdopodobną przyczyną jest to, że CLR ma specjalną wiedzę tej klasy. Jest to nieco przyziemne dla StringBuilder, w porównaniu do innych typów .NET, z którymi jest blisko, pinvoke marshaller wie, jak wygląda klasa. Używa się go, gdy trzeba przekazać referencję do kodu niezarządzanego, umożliwiając zapisanie treści ciągu. Konieczne, ponieważ nie jest to legalne dla String, jest niezmienne. Pinvoke marshaller wie, jak poprawnie ustawić wewnętrzne elementy StringBuilder po wywołaniu pinvoke. Ale nie wiedziałbym, jak to zrobić dla twojej pochodnej klasy. To ryzyko związane z krojeniem nie jest warte korzyści nieutrzymywania go. Zwłaszcza, że ​​nie ma metod wirtualnych, więc nie można w ogóle nadpisać jego zachowania.

Metoda rozszerzająca jest poza tym bardzo rozsądnym rozwiązaniem.

+0

może nie mieć niczego, co jest wirtualne, ale ma coś znacznie gorszego ... bezpośrednio publiczni członkowie, którzy są oznaczeni "wewnętrznie", nie ma pewności, jak CLR to rozwiąże ... lub czy uniemożliwiłoby to modyfikację klasy pochodnej im. – Mgetz

+0

To coś * bardzo * innego, po prostu oznacza, że ​​metoda jest zaimplementowana w C++ zamiast C#. Backgrounder [tutaj] (http://stackoverflow.com/questions/8870442/how-is-math-pow-implemented-in-net-framework/8870593#8870593) –

+0

"StringBuilder nie ma żadnych wirtualnych metod" trochę źle. Każdy obiekt zawiera wirtualne metody dla equals/hashcode i przesłonięcie tego (szczególnie w przypadku łańcucha) może spowodować awarię całego systemu. –

6

StringBuilder jest zaplombowany, ponieważ składa się z ciągów, np. nigdy nie powinno być powodu, aby go dziedziczyć, ponieważ każde użycie powinno mieć ograniczony zakres. StringBuilder nie jest zamiennikiem dla string i nigdy nie powinien być używany w ten sposób. Celem tej klasy było umożliwienie łatwej obsługi wszelkich operacji, które wymagały zmiennych łańcuchów bez ograniczenia wydajności. W związku z tym nie ma sposobu dziedziczenia z StringBuilder może dostarczyć jakiegokolwiek narzędzia i może stworzyć problemy z bezpieczeństwem, ponieważ klasa zajmuje się zmiennymi łańcuchami.

Spójrz na reference source nie jest to prosta klasa, ale ściśle ukierunkowane narzędzie. Ponadto robi rzeczy, które są unsafe, a tym samym pozwalając na dziedziczenie pozwoliłoby na modyfikację niebezpiecznego kodu, który mógłby zagrozić bezpieczeństwu.

+1

Rozumiem. Ale czy nie mogliby po prostu zapieczętować * niebezpieczne rzeczy do zignorowania *? Nie ma potrzeby całkowitego uszczelniania klasy. Poza tym większość członków zdaje się być wewnętrzna, więc dziedziczenie nawet ich nie pokazywało. – KappaG3

+0

@ KappaG3 przyjrzałeś się klasie ... 'unsafe' jest używany w prawie każdej funkcji. Celem była szybkość z bezpieczeństwem, a nie ekstensywność, ponieważ zakładano (całkiem słusznie, ponieważ nadal nie widziałem przypadku użycia), że nikt nie musiałby go przedłużać. – Mgetz

+4

@ KappaG3: ponieważ 'StringBuilder' jest przeznaczony do użycia wewnątrz metod do rozwiązania konkretnego zadania - buduj ciąg tu i teraz. Nie powinno to być nawet częścią kontraktu publicznego jakiegokolwiek typu. – Dennis