2010-05-03 10 views
14

robię kurs 3354 (wprowadzającej typów systemów i interfejsów w systemie .NET Framework 2.0) i mówi się, że do prostych zajęć, z członkami zmiennych i funkcji, to lepiej jest użyć struct niż klasa powodu napowietrznych."Overhead" klasy vs struktura w C#?

Nigdy nie słyszałem o czymś takim, jaki jest okres ważności tego roszczenia?

Odpowiedz

12

polecam nigdy używać struct chyba że masz bardzo specyficzny przypadków użycia w umyśle i dokładnie wiedzieć, w jaki sposób struktura będzie korzystać z systemu.

Podczas gdy struktura C# zezwala na członków, działają one nieco inaczej niż klasy (nie można podać podtypu, brak wirtualnej wysyłki, może żyć całkowicie na stosie), a zachowanie zmienia się w zależności od podnoszenia itp. (Podnoszenie to proces promowania typu wartości do sterty - niespodzianka!)

Tak więc, aby odpowiedzieć na pytanie: Myślę, że jeden z największych mylących w C# używa struktur "dla wydajności". Powodem tego jest "nadmiar", którego nie da się dokładnie zmierzyć, nie widząc, jak on współdziała z resztą systemu i rolą, jeśli cokolwiek z tego wynika, gra. Wymaga to profilowania i nie można go podsumować tak trywialnym stwierdzeniem, jak "mniejszy narzut".

Istnieje kilka przypadków dobrych dla typów wartości struct - jednym z przykładów jest złożona wartość RGB przechowywana w tablicy dla obrazu. Dzieje się tak, ponieważ typ RGB jest mały, może być na nim wiele obrazów, typy wartości mogą być dobrze zapakowane w tablice i mogą pomóc w utrzymaniu lepszej lokalizacji pamięci itp.

+0

Zakładam, że masz na myśli to, że nigdy nie zdefiniowałeś struktury. Prawdopodobnie używasz ich codziennie, nie myśląc o tym. – Gabe

+0

@Gabe Prawidłowo, naprawiłem to :-) –

+0

@pst: Myślę, że Gabe odnosi się do tego, co mówisz "Polecam, aby nigdy nie używać struktury". Oczywiście nie o to ci chodzi. –

0

struct to typ wartości, a klasa jest referencyjna. to może być jeden z powodów.

1

W języku C# klas i struktury są całkowicie różne zwierzęta. Składnia jest prawie identyczna dla obu, ale zachowanie jest zupełnie inne (wartość odniesienia względem wartości). Pojedyncza instancja struktury będzie zużywała mniej pamięci niż odpowiednia klasa, ale gdy zaczniesz budować kolekcje lub przekazywać je, semantyka typu wartości zabije cię pod względem wydajności (i ewentualnie zużycia pamięci w zależności od tego, co robisz), chyba że dane w strukturze są bardzo małe. Nie wiem, jaka jest twarda liczba, ale mówimy o 8-bajtowej lub mniejszej.

Może też boli w zakresie konserwacji i czytelność, ponieważ dwa wyglądać tak podobne, ale zachowują się zupełnie inaczej.

+0

Zalecany rozmiar jest mniejszy niż 16 bajtów. – ChaosPandion

+0

Ah, dzięki ChaosPandion! –

+0

To był brak obsługi optymalizatora dla typów wartości, który był zabójcą performace. Teraz, gdy to naprawiono (przynajmniej w architekturze x86), zanim pojawią się problemy z wydajnością, musisz mieć około 128 bajtów. –

-1

Nie ma potrzeby przydzielania/zwalniania struktur.

+1

-1: To nie jest prawdą w języku C#. –

+0

@JohnSaunders Może masz do tego referencje? Wszystko, co przeczytałem, wskazuje, że kompilator przydziela i zwolni struktury dla ciebie. Nadal je inicjujesz, ale to byłby inny problem. – Trisped

+0

Kompilator może zrobić to za Ciebie, ale to się robi. –

0

Dla prostych typów, w których będziesz mają wiele z nich, nie wymagają dziedziczenia i są dobrym kandydatem do bycia niezmiennymi, struktury są dobrym wyborem. Przykładami tego są Point, Rectangle, Decimal i DateTime.

Jeśli nie będzie miał wielu z nich, koszt jest bez znaczenia i nie powinien być czynnikiem w decyzji. Jeśli kiedykolwiek będziesz musiał czerpać z niego (lub uczynić go typem pochodnym), musi to być klasa. Jeśli element nie może być niezmienny, struct nie jest dobrym kandydatem, ponieważ mutacja jednej instancji nie zmieni żadnych jego kopii.

0

wierzę najczęściej cytowany punkt break-even jest około 12 bajtów danych w swojej struktury. Na przykład 3 liczby całkowite. Różnica między typem wartości a typem odniesienia jest jednak znacznie bardziej fundamentalna i powinieneś dokonać takiego wyboru na podstawie typów dla kilku członków.

Jeśli coś jest duże, to klasa :)

+0

Optymalizator został naprawiony kilka pakietów serwisowych temu, a teraz elementy są bardzo szybkie, powiedzmy 3 lub 4 podwójne (32 bajty). Nowy punkt progu rentowności jest nieco większy, przypuszczam 128 bajtów. –

2

Masz zamiar użyć klasy około 95% czasu. Semantyka typu wartości kończy się gryzieniem cię w tyłek częściej niż na drodze.

Jeśli jednak używasz struct, upewnij się, że jest niezmienny.

+3

Czy używasz struktur 5% czasu ?! : p – Pedery

8

Kiedy C# było w fazie beta, zostałem potraktowany jako demonstracja różnicy między klasą a strukturą. Twórcy stworzyli przeglądarkę Mandelbrot, która mierzy wiele liczb zespolonych, aby osiągnąć swój wynik. W pierwszej kolejności uruchomili kod z liczbami zespolonymi reprezentowanymi jako klasa z polem Real i Imaginary. Następnie zmienili słowo class na struct i ponownie skompilowali. Różnica w wydajności była ogromna.

Brak konieczności przydzielania obiektów sterty i konieczności ich usuwania w tym scenariuszu stanowiło różnicę. W zależności od tego, ile masz obiektów, różnica może być bardziej lub mniej spektakularna. Przed rozpoczęciem poprawiania zmierzyć wydajność i dopiero wtedy podjąć decyzję, aby przejść z typem wartości.

9

Powinieneś zasadniczo nie zmieniać typu, który powinien być klasą w strukturze ze względu na wydajność. Struktury i klasy mają inną semantykę i nie są dokładnie wymienne. To prawda, że ​​czasami struktury mogą być szybsze, ale czasami mogą być wolniejsze. Zachowują się inaczej i powinieneś rozpoznać, kiedy użyć jednego lub drugiego.

Witryna MSDN ma stronę pod adresem choosing between classes and structures.

Podsumowanie jest:

nie określają strukturę, chyba że rodzaj posiada wszystkie następujące cech:

  • To logicznie reprezentuje pojedynczą wartość, podobny do prymitywnych typów (liczba całkowita, podwójne i tak dalej).
  • Ma rozmiar wystąpienia mniejszy niż 16 bajtów.
  • Jest niezmienny.
  • Nie musi być często zapakowany.

Nie może czasami być przypadek, gdy typ naprawdę powinien być klasą, ale trzeba to być struktura ze względu na wydajność. Jest to rzadkie i powinieneś upewnić się, że wiesz, co robisz przed podjęciem tej trasy. Może to być szczególnie niebezpieczne w przypadku złamania wytycznych dotyczących niemożności dla struktur. Zmienne struktury mogą zachowywać się w sposób, jakiego większość programistów nie oczekuje.

+5

A teraz, gdy optymalizator obsługuje wstawianie dostępu do struct (co najmniej na x86), limit rozmiaru 16 bajtów nie jest już odpowiedni. Gdzieś około 128 bajtów jest prawdopodobnie dobrym nowym górnym limitem. –

0

Struktury są typami wartości, a klasy są typami odniesienia. Tak więc, jeśli zamierzasz przekazywać referencje, klasy mogą być lepsze pod względem wydajności, ponieważ kopiujesz adres, a nie całą strukturę. Jeśli jednak zamierzasz tworzyć instancje i odwoływać się do tych obiektów wiele razy, to będą one znacznie lepsze, ponieważ są przydzielane na stosie. Tak więc, struktura może być lepsza dla wielu obiektów, w których wydajność jest ważna lub w małych obiektach, gdzie pożądana jest semantyka typu wartości. Struktury również nie mają domyślnego konstruktora. Oni dziedziczą z Object, ale poza tym nie są dziedziczeni.

1

Jedna zasada można śledzić to, aby zadać sobie , czy to, co staramy się robić to jak System.Date jeśli nie jest, to należy naprawdę bardzo kwestionować swoją decyzję o wykorzystaniu konstrukcjom.