2009-09-10 11 views
7

Problemy są:C#: W jaki sposób należy zaimplementować ToString()?

  • biblioteki GUI lubią używać ToString jako domyślnej reprezentacji dla klas. Tam musi być zlokalizowane.
  • ToString służy do logowania. Tam powinien dostarczać informacje związane z programowaniem, nie jest tłumaczony i zawiera stany wewnętrzne, takie jak klucze zastępcze i wartości wyliczeniowe.
  • ToString jest używany przez wiele operacji łańcuchowych, które pobierają obiekty jako argumenty, na przykład String.Format, podczas zapisu do strumieni. W zależności od kontekstu oczekujesz czegoś innego.
  • ToString jest zbyt ograniczony, jeśli istnieje wiele różnych reprezentacji tego samego obiektu, np. długi i krótki formularz.

Ze względu na różne zastosowania, istnieje wiele różnych rodzajów realizacji. Są zbyt niewiarygodne, by być naprawdę przydatnym.

W jaki sposób należy wdrożyć ToString, aby było przydatne? Kiedy należy użyć ToString, kiedy powinno się go unikać?


The .NET Framework documentation mówi:

Ta metoda zwraca ludzki czytelny ciąg znaków, który jest wrażliwy na kulturę.

Istnieje similar question, ale nie to samo.

Odpowiedz

5

Wydaje masz wielkie nadzieje z to malutkie metody :) O ile wiem, to nie jest dobry pomysł, aby wykorzystać ogólny sposób w tak wielu różnych kontekstach specjalnie kiedy jego zachowanie może się różnić w zależności od klasy.

Oto moje propozycje:

1.Do nie pozwolić biblioteki GUI użyć toString() swojego objects.Instead użyć właściwości bardziej znaczące (prawie wszystkie kontrole mogą być dostosowywane, aby wyświetlić inne właściwości niż ToString) na przykład użyj DisplayMember. 2. Po otrzymaniu informacji o obiekcie (do logowania lub innych zastosowań) niech ktoś zdecyduje (inny obiekt lub sam obiekt), co powinno być dostarczone i jak powinien zostać wyświetlony. (Przydatny może być wzór strategii)

+0

Nie spodziewałbym się tak wiele, gdyby nie był on nazywany niejawnie w każdym miejscu. Ale prawdopodobnie masz rację. Powinienem unikać tego, że jest on pośrednio użyty w UI. –

1

Wszystko zależy od tego, w jaki sposób używasz swojej klasy. Wiele klas nie ma naturalnej reprezentacji ciągów znaków (np. Obiekt Form). Następnie zaimplementowałbym ToString jako metodę informacyjną (tekst, rozmiar itd.) Przydatny podczas debugowania. Jeśli klasa ma przekazywać informacje użytkownikowi, implementowałbym ToString jako domyślną reprezentację wartości. Jeśli masz obiekt Vector na przykład, ToString może zwrócić wektor jako współrzędną X i Y. Tutaj również dodałbym alternatywne metody, jeśli istnieją inne sposoby opisu klasy. Tak więc dla Vector mogę dodać metodę, która zwraca opis jako kąt i długość.

Do celów debugowania możesz również dodać atrybut DebuggerDisplay do swojej klasy. Mówi, jak wyświetlić klasę w debugerze, ale nie ma wpływu na reprezentację ciągów.

Możesz także rozważyć możliwość zwrócenia wartości przez ToString, aby można było je parsować, aby można było utworzyć obiekt z reprezentacji ciągów znaków. Podobnie jak w przypadku metody Int32.Parse.

0

Osobiście nie implementuję ToString tak często. W wielu przypadkach nie miałoby to większego sensu, ponieważ główną rolą typu może być definiowanie zachowania, a nie danych. W innych przypadkach po prostu nie ma to znaczenia, ponieważ nikt nie potrzebuje go nigdy.

W każdym razie, oto kilka przypadków, gdzie ma to sens (lista nie jest wyczerpująca):

  • Jeśli wynik mógłby ToString pomyślenia być analizowany z powrotem do instancji typu bez utraty danych.
  • Gdy typ ma prostą (tj. Niezłożoną) wartość.
  • Głównym celem tego typu jest formatowanie danych w tekście.

Nie zgadzam się, że istnieje sprzeczność między scenariuszami użycia, które wymieniasz. Kiedy głównym celem jest wyświetlanie, ToString powinien zapewniać tekst przyjazny dla użytkownika, ale dla rejestrowania (lub raczej, jak to opisujesz, dla śledzenia) powiedziałbym, że nie powinieneś śledzić elementu specyficznego dla interfejsu użytkownika w każdym przypadku, ale raczej obiekt, którego celem jest zapisanie szczegółowych danych śledzenia.

Nie ma konfliktu, ponieważ nie powinien być tego samego typu, zgodnie z zasadą odpowiedzialności pojedynczej.

Pamiętaj, że zawsze możesz przeciążyć metodę ToString, jeśli potrzebujesz większej kontroli.

+0

Problem polegający na tym, że "klient nigdy go nie potrzebuje" jest taki, że funkcja ToString jest wywoływana niejawnie. Konflikt powstaje, gdy ten sam obiekt jest używany w różnych sytuacjach. Czy DateTime to klasa specyficzna dla interfejsu użytkownika? Wiele klas nie jest zaprojektowanych do użycia wyłącznie w interfejsie użytkownika lub tylko wewnętrznie. "Zawsze możesz przeciążyć ToString": To jest pytanie: JAK powinno to zostać wdrożone? –

+0

Jeśli używasz tego samego obiektu w bardzo różnych sytuacjach, uważam, że naruszasz SRP ...Nie, DateTime nie jest szczególnie specyficzną dla UI klasą, ale należy do tej kategorii, w której można w obie strony wywoływać ToString/Parse bez utraty danych. –

1

Kolejną rzeczą, o której warto pamiętać, jest ścisła integracja debuggera ToString i Visual Studio. Okno obserwacyjne wyświetla wynik ToString jako wartość wyrażenia, więc jeśli twoja metoda wykonuje jakieś leniwego ładowania, ma żadnych skutków ubocznych lub trwa długo, może pojawić się dziwne zachowanie lub debugger może wydawać się zawiesić . Oczywiście, te cechy nie są oznaką dobrze zaprojektowanej metody ToString, ale występują (np. Naiwna implementacja "pobierz z bazy danych").

W związku z tym uważam domyślną metodę ToString (bez parametrów) za hak debugowania Visual Studio - z implikacją, że nie powinna być ona ogólnie przeciążona do użycia przez program poza kontekstem debugowania.

Podczas tych w dźwigni poznać atrybuty debugowania (DebuggerTypeProxyAttribute, DebuggerDisplayAttribute, DebuggerBrowsableAttribute), aby dostosować debugger, wielu (w tym ja) ogólnie rozważyć wyjście domyślnego jak generowane przez ToString i wyświetlane w oknach Watch być wystarczająco dobry.

Rozumiem, że jest to dość ścisła perspektywa - spisanie ToString jako haka debuggera - ale uważam, że wdrożenie IFormattable wydaje się być bardziej niezawodną i rozszerzalną trasą.

Powiązane problemy