Kiedy powinienem używać struktury zamiast klasy?

MSDN mówi, że powinieneś używać struktur, gdy potrzebujesz lekkich obiektów. Czy istnieją inne scenariusze, w których struktura jest lepsza od klasy?

Niektórzy mogli o tym zapomnieć:

  1. struktury mogą mieć metody.
  2. struktury nie mogą być dziedziczone.

Rozumiem techniczne różnice pomiędzy strukturami i klasami, po prostu nie mam dobrego wyczucia Kiedy używać struktury.

Author: Konrad Rudolph, 2008-09-17

14 answers

MSDN ma odpowiedź: Wybór pomiędzy klasami i strukturami .

Zasadniczo, ta strona daje 4-elementową listę kontrolną i mówi, aby używać klasy, chyba że Twój typ spełnia wszystkie kryteria.

Nie Definiuj struktury, chyba że Typ posiada wszystkie z następujących Charakterystyka:

  • logicznie przedstawia pojedynczą wartość, podobną do prymitywnych typów (liczba całkowita, Podwójna i tak dalej).
  • ma rozmiar wystąpienia mniejszy niż 16 bajtów.
  • Jest niezmienna.
  • nie będzie musiał być często pakowany.
 288
Author: OwenP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-26 21:58:51

Dziwię się, że nie przeczytałem żadnej z poprzednich odpowiedzi, które uważam za najistotniejsze:

Używam struktur, gdy chcę typu Bez tożsamości. Na przykład punkt 3D:

public struct ThreeDimensionalPoint
{
    public readonly int X, Y, Z;
    public ThreeDimensionalPoint(int x, int y, int z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }

    public override string ToString()
    {
        return "(X=" + this.X + ", Y=" + this.Y + ", Z=" + this.Z + ")";
    }

    public override int GetHashCode()
    {
        return (this.X + 2) ^ (this.Y + 2) ^ (this.Z + 2);
    }

    public override bool Equals(object obj)
    {
        if (!(obj is ThreeDimensionalPoint))
            return false;
        ThreeDimensionalPoint other = (ThreeDimensionalPoint)obj;
        return this == other;
    }

    public static bool operator ==(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
    {
        return p1.X == p2.X && p1.Y == p2.Y && p1.Z == p2.Z;
    }

    public static bool operator !=(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
    {
        return !(p1 == p2);
    }
}

Jeśli masz dwie instancje tej struktury, nie obchodzi cię, czy są one pojedynczym kawałkiem danych w pamięci czy dwoma. Po prostu dbasz o wartość (wartości), które posiadają.

 52
Author: Andrei Rînea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-13 15:11:32

Bill Wagner ma o tym rozdział w swojej książce "effective c#" ( http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660 ). konkluduje stosując następującą zasadę:

  1. czy główną odpowiedzialnością typu data storage?
  2. czy jego publiczny interfejs jest definiowany w całości przez właściwości, które uzyskują dostęp lub modyfikują jego elementy danych?
  3. Jesteś pewien, że Twój typ nigdy nie będzie miał podklas?
  4. czy jesteś pewien, że Twój typ nigdy być traktowane polimorficznie?

Jeśli odpowiesz "tak"na wszystkie 4 pytania: użyj struktury. W przeciwnym razie użyj klasy.

 25
Author: Bart Gijssens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-07 09:18:40

Użyj struktury, jeśli chcesz semantyki typu value zamiast typu reference. Struktury są kopiowane według wartości, więc bądź ostrożny!

Zobacz też poprzednie pytania, np.

Jaka jest różnica między strukturą a klasą w. Net?

 15
Author: Simon Steele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:07

Użyłbym structs gdy:

  1. Obiekt powinien być tylko do odczytu(za każdym razem, gdy przekazujesz / przypisujesz strukturę, zostanie ona skopiowana). Obiekty tylko do odczytu są świetne, jeśli chodzi o przetwarzanie wielowątkowe, ponieważ w większości przypadków nie wymagają blokowania.

  2. Obiekt jest mały i krótkotrwały. W takim przypadku istnieje duża szansa, że obiekt zostanie przydzielony na stosie, co jest o wiele bardziej efektywne niż umieszczenie go na stercie zarządzanej. Co więcej pamięć przydzielony przez obiekt zostanie uwolniony, gdy tylko wyjdzie poza jego zakres. Innymi słowy jest to mniej pracy dla Garbage Collector i pamięć jest używana bardziej wydajnie.

 10
Author: Pawel Pabich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 17:33:58

Użyj klasy, jeśli:

    Jego tożsamość jest ważna. Struktury są kopiowane niejawnie, gdy są przekazywane przez wartość do metody.
  • będzie miał duży ślad pamięci.
  • jego pola wymagają inicjalizatorów.
  • musisz dziedziczyć z klasy bazowej.
  • potrzebujesz zachowania polimorficznego;

Użyj struktury, Jeśli:

  • będzie działać jak prymitywny typ (int, long, byte, itp.).
  • musi mają mały ślad pamięci.
  • wywołujesz metodę P / Invoke, która wymaga przekazania struktury przez wartość.
  • należy zmniejszyć wpływ usuwania śmieci na wydajność aplikacji.
  • jego pola muszą być inicjowane tylko do ich wartości domyślnych. Wartość ta będzie równa zero dla typów liczbowych, false dla typów logicznych i null dla typów referencyjnych.
    • zauważ, że w C# 6.0 struktury mogą mieć domyślny konstruktor, który może być użyty do inicjalizacji na pola struct do wartości niezerowych.
  • nie musisz dziedziczyć z klasy bazowej (innej niż ValueType, z której wszystkie struktury dziedziczą).
  • nie potrzebujesz zachowania polimorficznego.
 7
Author: Yashwanth Chowdary Kata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-18 07:05:33

Zawsze używałem struktury, gdy chciałem zgrupować kilka wartości do przekazywania rzeczy z wywołania metody, ale nie będę musiał jej używać do niczego po przeczytaniu tych wartości. To tylko sposób na utrzymanie porządku. Zazwyczaj postrzegam rzeczy w strukturze jako "odrzucające", a rzeczy w klasie jako bardziej użyteczne i"funkcjonalne"

 5
Author: Ryan Skarin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 18:57:12

Jeśli encja ma być niezmienna, pytanie o to, czy użyć struktury czy klasy, będzie na ogół kwestią wydajności, a nie semantyki. W systemie 32/64-bitowym odwołania do klas wymagają przechowywania 4/8 bajtów, niezależnie od ilości informacji w klasie; kopiowanie odwołań do klas wymaga skopiowania 4/8 bajtów. Z drugiej strony, każda instancja klasy distinct będzie miała 8/16 bajtów narzutu oprócz przechowywanych informacji i kosztów pamięci odniesienia do niego. Załóżmy, że chcemy tablicy 500 jednostek, z których każdy zawiera cztery 32-bitowe liczby całkowite. Jeśli encja jest typem struktury, tablica będzie wymagała 8000 bajtów, niezależnie od tego, czy wszystkie 500 encji są identyczne, różne, czy gdzieś pomiędzy. Jeśli encja jest typem klasy, tablica 500 odwołań zajmie 4000 bajtów. Jeśli wszystkie odniesienia wskazują na różne obiekty, obiekty te wymagałyby dodatkowych 24 bajtów każdy (12 000 bajtów dla wszystkich 500), łącznie 16 000 bajtów-dwa razy więcej niż koszt przechowywania typu struct. Z drugiej strony, z kodu, który stworzył jedną instancję obiektu, a następnie skopiował odwołanie do wszystkich 500 slotów tablicy, całkowity koszt wynosiłby 24 bajty dla tej instancji i 4000 dla tablicy-łącznie 4024 bajty. Duże oszczędności. Niewiele sytuacji by się sprawdziło, ale w niektórych przypadkach może być możliwe skopiowanie niektórych odniesień do wystarczającej liczby gniazd tablicy, aby takie dzielenie się było warte zachodu.

Jeśli byt ma bądź zmienny, pytanie, czy używać klasy czy struktury, jest w pewnym sensie łatwiejsze. Załóżmy, że" rzecz " jest strukturą lub klasą, która ma pole całkowite o nazwie x i wykonujemy następujący kod:

  Thing t1,t2;
  ...
  t2 = t1;
  t2.x = 5;

Czy ktoś chce, aby to ostatnie stwierdzenie miało wpływ na t1.x?

Jeśli rzecz jest typem klasy, T1 i t2 będą równoważne, czyli t1.x i t2.x będzie również równoważne. Tak więc drugie stwierdzenie wpłynie na t1.x. Jeśli rzecz jest typem struktury, T1 i t2 będą różnymi instancjami, czyli t1.x i t2.x będzie odnosił się do różnych liczb całkowitych. Tak więc drugie stwierdzenie nie będzie miało wpływu na t1.x.

Mutable structions i mutable classes mają zasadniczo różne zachowania, choć. NET ma pewne dziwactwa w obchodzeniu się z mutacjami struct. Jeśli ktoś chce zachowania typu wartości (co oznacza, że "t2=t1" skopiuje dane z t1 do t2, pozostawiając T1 i t2 jako odrębne instancje), i jeśli można żyć z dziwactwami w obsłudze typów wartości. NET, użyj struktury. Jeśli jeden chce semantyki typu value, ale dziwactwa. NET spowodowałyby złamanie semantyki typu value w swojej aplikacji, użycie klasy i mumble.

 4
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-18 19:26:31

DODATKOWO doskonałe odpowiedzi powyżej:

Struktury są typami wartości.

Nigdy nie mogą być ustawione na nic .

Ustawienie struktury = Nothing spowoduje ustawienie wszystkich typów wartości na ich domyślne wartości.

 3
Author: George Filippakos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 08:04:09

Kiedy tak naprawdę nie potrzebujesz zachowania, ale potrzebujesz więcej struktury niż zwykła tablica lub słownik.

Follow up Tak myślę o strukturach w ogóle. Wiem, że mogą mieć metody, ale lubię zachować to ogólne rozróżnienie umysłowe.

 2
Author: Jim Deville,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 18:08:35

Jak powiedział @ Simon, struktury zapewniają semantykę typu "value-type", więc jeśli potrzebujesz zachowania podobnego do wbudowanego typu danych, użyj struktury. Ponieważ struktury są przekazywane przez copy, należy się upewnić, że mają mały rozmiar, około 16 bajtów.

 2
Author: Scott Dorman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-16 14:40:57

Hmm...

Nie użyłbym garbage collection jako argumentu za/przeciw użyciu struktur vs klas. Zarządzana sterta działa podobnie jak stos - tworzenie obiektu po prostu umieszcza go na szczycie sterty, co jest prawie tak szybkie, jak przydzielanie na stosie. Dodatkowo, jeśli obiekt jest krótkotrwały i nie przetrwa cyklu GC, dealokacja jest bezpłatna, ponieważ GC działa tylko z pamięcią, która jest nadal dostępna. (Szukaj MSDN, jest seria artykułów na temat zarządzania pamięcią. NET, jestem po prostu zbyt leniwy, aby iść kopać dla nich).

Przez większość czasu używam struktury, kończę się za to kopaniem, ponieważ później odkrywam, że posiadanie semantyki referencyjnej byłoby nieco prostsze.

W każdym razie te cztery punkty w artykule MSDN zamieszczonym powyżej wydają się dobrą wskazówką.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 19:06:52

Struktury są na stosie, a nie na stercie, dlatego są bezpieczne dla wątków i powinny być używane podczas implementacji wzorca obiektu transferu, nigdy nie chcesz używać obiektów na stercie są one lotne, chcesz w tym przypadku użyć stosu wywołań, jest to podstawowy przypadek użycia struktury jestem zaskoczony wszystkimi odpowiedziami tutaj,

 1
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-18 17:33:45

Myślę, że najlepszą odpowiedzią jest użycie struct, gdy potrzebujesz kolekcji właściwości, klasy, gdy jest to kolekcja właściwości i zachowań.

 -2
Author: Lucian Gabriel Popescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-05 16:51:17