Jaka jest różnica między strukturą a klasą in.NET?

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

Author: Mark Amery, 2008-08-16

19 answers

W. NET istnieją dwie kategorie typów, typy referencyjne i typy wartości .

Struktury to typy wartości , A klasy to typy referencyjne.

Ogólna różnica polega na tym, że typ odniesienia żyje na stercie, A Typ wartości żyje w linii, czyli wszędzie tam, gdzie jest zdefiniowana twoja zmienna lub pole.

Zmienna zawierająca typ wartości zawiera cały typ wartości wartość. Dla struktury, oznacza to, że zmienna zawiera całą strukturę wraz ze wszystkimi jej polami.

Zmienna zawierająca Typ odniesienia zawiera wskaźnik, lub odniesienie do innego miejsca w pamięci, w którym znajduje się rzeczywista wartość.

To ma jedną zaletę, na początek:

  • typy wartości zawsze zawiera wartość
  • typy referencji mogą zawierać null -reference, co oznacza, że w ogóle nie odnoszą się do niczego w moment

Wewnętrznie, Typ odniesienia S są zaimplementowane jako wskaźniki, a wiedząc, że i wiedząc, jak działa przypisanie zmiennych, istnieją inne wzorce zachowań:

  • kopiowanie zawartości zmiennej typu wartości do innej zmiennej, kopiowanie całej zawartości do nowej zmiennej, czyniąc obie zmienne odrębnymi. Innymi słowy, po skopiowaniu zmiany na jeden nie będą miały wpływu na drugi
  • kopiowanie zawartości typu odniesienia zmienna do innej zmiennej kopiuje odniesienie, co oznacza, że teraz masz dwa odniesienia do tego samego gdzie indziej przechowywania rzeczywistych danych. Innymi słowy, po skopiowaniu zmiana danych w jednym odwołaniu wydaje się wpływać również na inne, ale tylko dlatego, że tak naprawdę patrzysz na te same dane w obu miejscach

Kiedy deklarujesz zmienne lub pola, oto jak te dwa typy różnią się:

  • zmienna: typ wartości żyje na stosie, Typ odniesienia żyje na stosie jako wskaźnik do miejsca w pamięci sterty, w którym mieszka prawdziwa pamięć (chociaż Uwaga seria artykułów Erica Lippertsa: stos jest szczegółem implementacji .)
  • class / struct-field: value typeżyje całkowicie wewnątrz typu, reference type żyje wewnątrz typu jako wskaźnik do miejsca w pamięci sterty, gdzie mieszka rzeczywista pamięć.
 1115
Author: Lasse V. Karlsen,
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-12-20 11:47:03

Krótkie podsumowanie każdego:

Tylko Klasy:

  • może obsługiwać dziedziczenie
  • są typami referencyjnymi (wskaźnikowymi)
  • odniesienie może być null
  • mają narzut pamięci na nową instancję

Tylko Structs:

  • nie można wspierać dziedziczenia
  • są typami wartości
  • są przekazywane przez wartość (jak liczby całkowite)
  • nie może mieć referencji null (chyba że użyto Nullable)
  • nie mają nadmiarowej pamięci na new instance-unless 'boxed'

Zarówno klasy jak i struktury:

  • są złożonymi typami danych Zwykle używanymi do przechowywania kilku zmiennych, które mają pewną logiczną relację
  • może zawierać metody i zdarzenia
  • może obsługiwać interfejsy
 218
Author: Thomas Bratt,
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
2012-06-07 15:49:45

W. NET deklaracje struct I class rozróżniają typy referencyjne i typy wartości.

Kiedy mijasz Typ odniesienia, jest tylko jeden faktycznie przechowywany. Cały kod, który uzyskuje dostęp do instancji, ma dostęp do tego samego.

Kiedy przekazujesz typ wartości, każdy z nich jest kopią. Cały kod działa na własnej kopii.

Można to pokazać na przykładzie:

struct MyStruct 
{
    string MyProperty { get; set; }
}

void ChangeMyStruct(MyStruct input) 
{ 
   input.MyProperty = "new value";
}

...

// Create value type
MyStruct testStruct = new MyStruct { MyProperty = "initial value" }; 

ChangeMyStruct(testStruct);

// Value of testStruct.MyProperty is still "initial value"
// - the method changed a new copy of the structure.

Dla klasy to byłoby inne

class MyClass 
{
    string MyProperty { get; set; }
}

void ChangeMyClass(MyClass input) 
{ 
   input.MyProperty = "new value";
}

...

// Create reference type
MyClass testClass = new MyClass { MyProperty = "initial value" };

ChangeMyClass(testClass);

// Value of testClass.MyProperty is now "new value" 
// - the method changed the instance passed.

Klasy mogą być nic - odniesienie może wskazywać na null.

Struktury są rzeczywistą wartością - mogą być puste, ale nigdy nie null. Z tego powodu struktury zawsze mają domyślny konstruktor bez parametrów - potrzebują 'wartości początkowej'.

 46
Author: Keith,
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
2015-04-06 11:39:33

Różnica między strukturami a klasami:

  • struktury są typem wartości, podczas gdy Klasy są typem odniesienia .
  • struktury są przechowywane na stosie , podczas gdy klasy są przechowywane na heap .
  • typy wartości przechowują swoją wartość w pamięci, gdzie są zadeklarowane, ale Typ odniesienia zawiera odniesienie do pamięci obiektu.
  • typy wartości zniszczone natychmiast po utracie zakresu Typ odniesienia tylko zmienna zniszczyć po zgubieniu lunety. Na obiekt jest później niszczony przez garbage collector.
  • Kiedy skopiujesz struct do innej struktury, nowa kopia tej struktury gets created modified of one struct won ' t affect the value of the inne struktury.
  • Kiedy kopiujesz klasę do innej klasy, kopiuje ona tylko zmienna odniesienia.
  • obie wartości odnoszą się do tego samego obiektu na stercie. Zmiana na jedną zmienną wpłynie na inne odniesienie zmienna.
  • struktury nie mogą mieć destruktorów , ale klasy mogą mieć destruktory.
  • struktury nie mogą mieć jawnych konstruktorów bez parametru , podczas gdy klasy mogą. Struktury nie wspierają dziedziczenia, ale klasy tak. Obie wsparcie dziedziczenia z interfejsu.
  • struktury są typu zamkniętego .
 28
Author: shana,
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
2020-10-30 18:27:09

From Microsoft ' s Choosing Between Class and Struct ...

Z reguły większość typów w ramach powinna być klasy. Są jednak sytuacje, w których cechy typu wartości sprawiają, że bardziej odpowiednie jest użycie struktury.

rozważmy strukturę zamiast klasy:

  • Jeśli instancje tego typu są małe i zwykle krótkotrwałe lub są powszechnie osadzone w innych obiektów.

X unikaj struktury , chyba że typ ma wszystkie z następujących Charakterystyka:

  • logicznie przedstawia pojedynczą wartość, podobną do prymitywnych typów (int, double, itp.).
  • ma rozmiar instancji poniżej 16 bajtów.
  • Jest niezmienna. (nie można zmienić)
  • nie będzie musiał być często pakowany.
 22
Author: Sunsetquest,
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-14 19:58:36

Oprócz wszystkich różnic opisanych w pozostałych odpowiedziach:

  1. struktury nie mogą mieć jawnego konstruktora bez parametru , podczas gdy klasa może
  2. struktury nie mogą mieć destruktorów , podczas gdy klasa może
  3. struktury nie mogą dziedziczyć z innej struktury lub klasy, podczas gdy klasa może dziedziczyć z innej klasy. (Zarówno struktury jak i klasy mogą zaimplementować z poziomu interfejsu.)

Jeśli szukasz filmu wyjaśniającego wszystkie różnice, można sprawdzić część 29-samouczek C# - różnica między klasami i strukturami w C#.

 19
Author: Venkat,
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-12-21 18:31:06

Instancje klas są przechowywane na stercie zarządzanej. Wszystkie zmienne "zawierające" instancję są po prostu odniesieniem do instancji na stercie. Przekazanie obiektu do metody powoduje przekazanie kopii odniesienia, a nie samego obiektu.

Struktury (technicznie typy wartości) są przechowywane wszędzie tam, gdzie są używane, podobnie jak typ prymitywny. Zawartość może być kopiowana przez runtime w dowolnym momencie i bez wywoływania niestandardowego konstruktora kopiującego. Przekazywanie typu wartości do metoda polega na skopiowaniu całej wartości, ponownie bez wywoływania jakiegokolwiek konfigurowalnego kodu.

Rozróżnienie jest lepsze dzięki nazwom C++ / CLI: "Klasa ref" jest klasą opisaną jako pierwsza, "klasa wartości" jest klasą opisaną jako druga. Słowa kluczowe "class" i "struct" używane przez C# są po prostu czymś, czego trzeba się nauczyć.

 16
Author: Zooba,
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-08-16 12:16:50
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|                        |                                                Struct                                                |                                               Class                                               |
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
| Type                   | Value-type                                                                                           | Reference-type                                                                                    |
| Where                  | On stack / Inline in containing type                                                                 | On Heap                                                                                           |
| Deallocation           | Stack unwinds / containing type gets deallocated                                                     | Garbage Collected                                                                                 |
| Arrays                 | Inline, elements are the actual instances of the value type                                          | Out of line, elements are just references to instances of the reference type residing on the heap |
| Aldel Cost             | Cheap allocation-deallocation                                                                        | Expensive allocation-deallocation                                                                 |
| Memory usage           | Boxed when cast to a reference type or one of the interfaces they implement,                         | No boxing-unboxing                                                                                |
|                        | Unboxed when cast back to value type                                                                 |                                                                                                   |
|                        | (Negative impact because boxes are objects that are allocated on the heap and are garbage-collected) |                                                                                                   |
| Assignments            | Copy entire data                                                                                     | Copy the reference                                                                                |
| Change to an instance  | Does not affect any of its copies                                                                    | Affect all references pointing to the instance                                                    |
| Mutability             | Should be immutable                                                                                  | Mutable                                                                                           |
| Population             | In some situations                                                                                   | Majority of types in a framework should be classes                                                |
| Lifetime               | Short-lived                                                                                          | Long-lived                                                                                        |
| Destructor             | Cannot have                                                                                          | Can have                                                                                          |
| Inheritance            | Only from an interface                                                                               | Full support                                                                                      |
| Polymorphism           | No                                                                                                   | Yes                                                                                               |
| Sealed                 | Yes                                                                                                  | When have sealed keyword                                                                          |
| Constructor            | Can not have explicit parameterless constructors                                                     | Any constructor                                                                                   |
| Null-assignments       | When marked with nullable question mark                                                              | Yes (+ When marked with nullable question mark in C# 8+)                                          |
| Abstract               | No                                                                                                   | When have abstract keyword                                                                        |
| Member Access Modifiers| public, private, internal                                                                            | public, protected, internal, protected internal, private protected                                |
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
 12
Author: Avestura,
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
2020-03-27 13:21:19

I ♥ wizualizacje, a tutaj stworzyłem jedną, aby pokazać podstawowe różnice między strukturamii klasami. Tutaj wpisz opis obrazka


Więcej informacji znajdziesz poniżej:

 11
Author: Arsen Khachaturyan,
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
2020-06-18 16:49:57

Struktura vs Klasa

Struktura jest typem wartości, więc jest przechowywana na stosie, ale klasa jest typem odniesienia i jest przechowywana na stosie.

Struktura nie wspiera dziedziczenia i polimorfizmu, ale Klasa wspiera oba.

Domyślnie wszystkie członkowie struktury są publiczne, ale członkowie klasy są domyślnie prywatnymi.

Ponieważ struktura jest typem wartości, nie możemy przypisać null do obiektu struct, ale tak nie jest w przypadku klasy.

 9
Author: Swagatika dhal,
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
2015-04-06 11:43:02

Aby dodać do innych odpowiedzi, jest jedna zasadnicza różnica, na którą warto zwrócić uwagę, a mianowicie sposób przechowywania danych w tablicach, ponieważ może to mieć duży wpływ na wydajność.

  • W przypadku struktury tablica zawiera instancję struktury
  • W przypadku klasy tablica zawiera wskaźnik do instancji klasy w innym Miejscu Pamięci

Więc tablica struktur wygląda tak w pamięci

[struct][struct][struct][struct][struct][struct][struct][struct]

Natomiast tablica klas wygląda like this

[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]

W przypadku tablicy klas, wartości, które Cię interesują, nie są przechowywane w tablicy, ale gdzie indziej w pamięci.

Dla zdecydowanej większości aplikacji różnica ta tak naprawdę nie ma znaczenia, jednak w kodzie o wysokiej wydajności wpłynie to na lokalizację danych w pamięci i będzie miało duży wpływ na wydajność pamięci podręcznej procesora. Używanie klas, gdy można/powinno się używać struktur, znacznie zwiększy liczbę braków pamięci podręcznej na CPU.

Najwolniejszą rzeczą, jaką robi współczesny procesor, nie jest chrupanie liczb, tylko pobieranie danych z pamięci, a pamięć podręczna L1 jest wielokrotnie szybsza niż odczyt danych z pamięci RAM.

Oto kod, który możesz przetestować. Na moim komputerze iteracja przez tablicę klas trwa ~3x dłużej niż tablica struct.
    private struct PerformanceStruct
    {
        public int i1;
        public int i2;
    }

    private class PerformanceClass
    {
        public int i1;
        public int i2;
    }

    private static void DoTest()
    {
        var structArray = new PerformanceStruct[100000000];
        var classArray = new PerformanceClass[structArray.Length];

        for (var i = 0; i < structArray.Length; i++)
        {
            structArray[i] = new PerformanceStruct();
            classArray[i] = new PerformanceClass();
        }

        long total = 0;
        var sw = new Stopwatch();
        sw.Start();
        for (var loops = 0; loops < 100; loops++)
        for (var i = 0; i < structArray.Length; i++)
        {
            total += structArray[i].i1 + structArray[i].i2;
        }

        sw.Stop();
        Console.WriteLine($"Struct Time: {sw.ElapsedMilliseconds}");
        sw = new Stopwatch();
        sw.Start();
        for (var loops = 0; loops < 100; loops++)
        for (var i = 0; i < classArray.Length; i++)
        {
            total += classArray[i].i1 + classArray[i].i2;
        }

        Console.WriteLine($"Class Time: {sw.ElapsedMilliseconds}");
    }
 9
Author: Will Calderwood,
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
2020-04-24 10:20:09

Aby była kompletna, jest jeszcze jedna różnica przy użyciu metody Equals, która jest dziedziczona przez wszystkie klasy i struktury.

Powiedzmy, że mamy klasę i strukturę:

class A{
  public int a, b;
}
struct B{
  public int a, b;
}

I w głównej metodzie mamy 4 obiekty.

static void Main{
  A c1 = new A(), c2 = new A();
  c1.a = c1.b = c2.a = c2.b = 1;
  B s1 = new B(), s2 = new B();
  s1.a = s1.b = s2.a = s2.b = 1;
}

Wtedy:

s1.Equals(s2) // true
s1.Equals(c1) // false
c1.Equals(c2) // false
c1 == c2 // false

Tak więc, struktury są odpowiednie dla obiektów numerycznych, takich jak punkty(Zapisz współrzędne x i y). A zajęcia są odpowiednie dla innych. Nawet jeśli 2 osoby mają to samo imię, wzrost, wagę..., są nadal 2 osoby.

 7
Author: Ning,
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-12-16 23:50:23

Cóż, na początek, struktura jest przekazywana przez wartość, a nie przez odniesienie. Struktury są dobre dla stosunkowo prostych struktur danych, podczas gdy klasy mają o wiele większą elastyczność z architektonicznego punktu widzenia poprzez polimorfizm i dziedziczenie.

Inni mogą prawdopodobnie podać więcej szczegółów niż ja, ale używam struktur, gdy struktura, do której zmierzam, jest prosta.

 6
Author: Ed S.,
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-08-16 08:27:14

Oprócz podstawowej różnicy w specyfikatorze dostępu i kilku wymienionych powyżej chciałbym dodać kilka głównych różnic, w tym kilka z wymienionych powyżej z próbką kodu z wyjściem, co da bardziej jasne wyobrażenie o referencji i wartości

Structs:

  • są typami wartości i nie wymagają alokacji sterty.
  • alokacja pamięci jest inna i jest przechowywana w stosie
  • przydatne dla małych struktur danych
  • Afekt wydajność, kiedy przekazujemy wartość do metody, przekazujemy całą strukturę danych i wszystkie są przekazywane do stosu.
  • Konstruktor po prostu zwraca samą wartość struct (zazwyczaj w tymczasowej lokalizacji na stosie), a wartość ta jest następnie kopiowana w razie potrzeby
  • każda ze zmiennych ma swoją własną kopię danych, a operacje na jednej z nich nie mogą wpływać na drugą.
  • nie obsługują dziedziczenia określonego przez użytkownika i w domyśle dziedziczą od typu obiekt

Klasa:

  • wartość typu odniesienia
  • przechowywany w stercie
  • przechowuje odniesienie do dynamicznie przydzielanego obiektu
  • konstruktory są wywoływane z nowym operatorem, ale to nie przydziela pamięci na stercie
  • wiele zmiennych może mieć odniesienie do tego samego obiektu
  • operacje na jednej zmiennej mogą wpływać na obiekt, do którego odnosi się druga zmienna

Kod Próbka

    static void Main(string[] args)
    {
        //Struct
        myStruct objStruct = new myStruct();
        objStruct.x = 10;
        Console.WriteLine("Initial value of Struct Object is: " + objStruct.x);
        Console.WriteLine();
        methodStruct(objStruct);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Struct Object is: " + objStruct.x);
        Console.WriteLine();

        //Class
        myClass objClass = new myClass(10);
        Console.WriteLine("Initial value of Class Object is: " + objClass.x);
        Console.WriteLine();
        methodClass(objClass);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Class Object is: " + objClass.x);
        Console.Read();
    }
    static void methodStruct(myStruct newStruct)
    {
        newStruct.x = 20;
        Console.WriteLine("Inside Struct Method");
        Console.WriteLine("Inside Method value of Struct Object is: " + newStruct.x);
    }
    static void methodClass(myClass newClass)
    {
        newClass.x = 20;
        Console.WriteLine("Inside Class Method");
        Console.WriteLine("Inside Method value of Class Object is: " + newClass.x);
    }
    public struct myStruct
    {
        public int x;
        public myStruct(int xCons)
        {
            this.x = xCons;
        }
    }
    public class myClass
    {
        public int x;
        public myClass(int xCons)
        {
            this.x = xCons;
        }
    }

Output

Wartość początkowa obiektu Struct wynosi: 10

Wewnątrz Metody Struct Wewnątrz metody wartość obiektu Struct wynosi: 20

Po wywołaniu metody wartość obiektu Struct wynosi: 10

Wartość początkowa obiektu klasy to: 10

Inside Class Method Wewnątrz metody wartość obiektu klasy wynosi: 20

Po wywołaniu metody wartość obiektu klasy jest: 20

Tutaj wyraźnie widać różnicę między wywołaniem przez wartość i wywołanie przez odniesienie.

 4
Author: Arijit Mukherjee,
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-30 22:27:23
  1. Zdarzenia zadeklarowane w klasie mają swój dostęp += i -= automatycznie zablokowane poprzez blokadę (this), aby uczynić je bezpiecznym wątkiem (zdarzenia statyczne są zablokowane na typ klasy). Zdarzenia zadeklarowane w strukturze nie mają automatycznie zablokowanego dostępu += i -=. Blokada (this) dla struktury nie będzie działać, ponieważ można zablokować tylko wyrażenie typu odniesienia.

  2. Utworzenie instancji struct nie może spowodować usunięcia śmieci (chyba że konstruktor bezpośrednio lub pośrednio tworzy instancję reference type), podczas gdy utworzenie instancji reference type może spowodować usuwanie śmieci.

  3. Struktura zawsze ma wbudowany publiczny konstruktor domyślny.

    class DefaultConstructor
    {
        static void Eg()
        {
            Direct     yes = new   Direct(); // Always compiles OK
            InDirect maybe = new InDirect(); // Compiles if constructor exists and is accessible
            //...
        }
    }
    

    Oznacza to, że struktura jest zawsze instancyjna, podczas gdy klasa może nie być, ponieważ wszystkie jej konstruktory mogą być prywatne.

    class NonInstantiable
    {
        private NonInstantiable() // OK
        {
        }
    }
    
    struct Direct
    {
        private Direct() // Compile-time error
        {
        }
    }
    
  4. Struktura nie może mieć destruktora. Destruktor to tylko nadpisanie obiektu.Finalizuj w ukryciu, a struktury, będące typami wartości, nie są podlega zbiórce śmieci.

    struct Direct
    {
        ~Direct() {} // Compile-time error
    }
    class InDirect
    {
        ~InDirect() {} // Compiles OK
    }
    
    And the CIL for ~Indirect() looks like this:
    
    .method family hidebysig virtual instance void
            Finalize() cil managed
    {
      // ...
    } // end of method Indirect::Finalize
    
  5. Struktura jest niejawnie zamknięta, a klasa Nie.
    Struktura nie może być abstrakcyjna, klasa może.
    Struktura nie może wywołać : base() w swoim konstruktorze, podczas gdy Klasa bez jawnej klasy bazowej może.
    Struktura nie może rozszerzyć innej klasy, A klasa może.
    Struktura nie może deklarować chronionych członków (na przykład pól, zagnieżdżonych typów), A klasa może.
    Struktura nie może deklarować abstrakcyjnych członków funkcji, może to zrobić klasa abstrakcyjna.
    Struktura nie może deklarować wirtualnych członków funkcji, a klasa może.
    Struktura nie może deklarować zamkniętych członków funkcji, a klasa może.
    Struktura nie może zadeklarować zastępczych członków funkcji, a klasa może.
    Jedynym wyjątkiem od tej reguły jest to, że struktura może nadpisać wirtualne metody systemu.Object, Viz, Equals(), GetHashCode () i ToString ().

 4
Author: Zain Ali,
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
2015-04-06 11:46:57

Jak wspomniano wcześniej: klasy są typem referencyjnym, podczas gdy struktury są typami wartości ze wszystkimi konsekwencjami.

Jako kciuk Rule Framework Design Guidelines zaleca używanie struktur zamiast klas, jeśli:

  • ma rozmiar instancji poniżej 16 bajtów
  • logicznie przedstawia pojedynczą wartość, podobną do prymitywnych typów (int, double, itp.)
  • jest niezmienna
  • nie będzie musiał być często pakowany
 4
Author: kb9,
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
2015-09-23 11:32:37

Jest jeden interesujący przypadek zagadki "class vs struct" - sytuacja, w której musisz zwrócić kilka wyników z metody: wybierz, którego chcesz użyć. Jeśli znasz historię ValueTuple-wiesz, że ValueTuple (struct) została dodana, ponieważ powinna być bardziej efektywna niż Tuple (class). Ale co to oznacza w liczbach? Dwa testy: jeden to struct / class, który ma 2 pola, drugi z struct / class, który ma 8 pól (o wymiarze większym niż 4-klasa powinna stać się bardziej efektywna niż struct jeśli chodzi o kleszcze procesora, ale oczywiście obciążenie GC również powinno być brane pod uwagę).

P. S. kolejny benchmark dla konkretnego przypadku "sturct lub klasa ze zbiorami" jest tam: https://stackoverflow.com/a/45276657/506147

BenchmarkDotNet=v0.10.10, OS=Windows 10 Redstone 2 [1703, Creators Update] (10.0.15063.726)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233540 Hz, Resolution=309.2586 ns, Timer=TSC
.NET Core SDK=2.0.3
  [Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
  Clr    : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2115.0
  Core   : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT


            Method |  Job | Runtime |     Mean |     Error |    StdDev |      Min |      Max |   Median | Rank |  Gen 0 | Allocated |
------------------ |----- |-------- |---------:|----------:|----------:|---------:|---------:|---------:|-----:|-------:|----------:|
  TestStructReturn |  Clr |     Clr | 17.57 ns | 0.1960 ns | 0.1834 ns | 17.25 ns | 17.89 ns | 17.55 ns |    4 | 0.0127 |      40 B |
   TestClassReturn |  Clr |     Clr | 21.93 ns | 0.4554 ns | 0.5244 ns | 21.17 ns | 23.26 ns | 21.86 ns |    5 | 0.0229 |      72 B |
 TestStructReturn8 |  Clr |     Clr | 38.99 ns | 0.8302 ns | 1.4097 ns | 37.36 ns | 42.35 ns | 38.50 ns |    8 | 0.0127 |      40 B |
  TestClassReturn8 |  Clr |     Clr | 23.69 ns | 0.5373 ns | 0.6987 ns | 22.70 ns | 25.24 ns | 23.37 ns |    6 | 0.0305 |      96 B |
  TestStructReturn | Core |    Core | 12.28 ns | 0.1882 ns | 0.1760 ns | 11.92 ns | 12.57 ns | 12.30 ns |    1 | 0.0127 |      40 B |
   TestClassReturn | Core |    Core | 15.33 ns | 0.4343 ns | 0.4063 ns | 14.83 ns | 16.44 ns | 15.31 ns |    2 | 0.0229 |      72 B |
 TestStructReturn8 | Core |    Core | 34.11 ns | 0.7089 ns | 1.4954 ns | 31.52 ns | 36.81 ns | 34.03 ns |    7 | 0.0127 |      40 B |
  TestClassReturn8 | Core |    Core | 17.04 ns | 0.2299 ns | 0.2150 ns | 16.68 ns | 17.41 ns | 16.98 ns |    3 | 0.0305 |      96 B |

Test kodu:

using System;
using System.Text;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
using BenchmarkDotNet.Attributes.Jobs;
using DashboardCode.Routines.Json;

namespace Benchmark
{
    //[Config(typeof(MyManualConfig))]
    [RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
    [ClrJob, CoreJob]
    [HtmlExporter, MarkdownExporter]
    [MemoryDiagnoser]
    public class BenchmarkStructOrClass
    {
        static TestStruct testStruct = new TestStruct();
        static TestClass testClass = new TestClass();
        static TestStruct8 testStruct8 = new TestStruct8();
        static TestClass8 testClass8 = new TestClass8();
        [Benchmark]
        public void TestStructReturn()
        {
            testStruct.TestMethod();
        }

        [Benchmark]
        public void TestClassReturn()
        {
            testClass.TestMethod();
        }


        [Benchmark]
        public void TestStructReturn8()
        {
            testStruct8.TestMethod();
        }

        [Benchmark]
        public void TestClassReturn8()
        {
            testClass8.TestMethod();
        }

        public class TestStruct
        {
            public int Number = 5;
            public struct StructType<T>
            {
                public T Instance;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance;
            }

            private StructType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private StructType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private StructType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private StructType<int> Method4(int i)
            {
                var x = new StructType<int>();
                x.List = new List<string>();
                x.Instance = ++i;
                return x;
            }
        }

        public class TestClass
        {
            public int Number = 5;
            public class ClassType<T>
            {
                public T Instance;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance;
            }

            private ClassType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private ClassType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private ClassType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private ClassType<int> Method4(int i)
            {
                var x = new ClassType<int>();
                x.List = new List<string>();
                x.Instance = ++i;
                return x;
            }
        }

        public class TestStruct8
        {
            public int Number = 5;
            public struct StructType<T>
            {
                public T Instance1;
                public T Instance2;
                public T Instance3;
                public T Instance4;
                public T Instance5;
                public T Instance6;
                public T Instance7;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance1;
            }

            private StructType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private StructType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private StructType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private StructType<int> Method4(int i)
            {
                var x = new StructType<int>();
                x.List = new List<string>();
                x.Instance1 = ++i;
                return x;
            }
        }

        public class TestClass8
        {
            public int Number = 5;
            public class ClassType<T>
            {
                public T Instance1;
                public T Instance2;
                public T Instance3;
                public T Instance4;
                public T Instance5;
                public T Instance6;
                public T Instance7;
                public List<string> List;
            }

            public int TestMethod()
            {
                var s = Method1(1);
                return s.Instance1;
            }

            private ClassType<int> Method1(int i)
            {
                return Method2(++i);
            }

            private ClassType<int> Method2(int i)
            {
                return Method3(++i);
            }

            private ClassType<int> Method3(int i)
            {
                return Method4(++i);
            }

            private ClassType<int> Method4(int i)
            {
                var x = new ClassType<int>();
                x.List = new List<string>();
                x.Instance1 = ++i;
                return x;
            }
        }
    }
}
 3
Author: Roman Pokrovskij,
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-12-20 20:49:30

Struktury są rzeczywistą wartością - mogą być puste, ale nigdy nie null

To prawda, jednak zauważ również, że począwszy od struktury.NET 2 obsługują wersję Nullable, A C# dostarcza trochę cukru składniowego, aby ułatwić korzystanie z niej.

int? value = null;
value  = 1;
 2
Author: denis phillips,
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-08-16 14:03:02

Każda zmienna lub pole prymitywnego typu wartości lub struktury posiada unikalną instancję tego typu, w tym wszystkie jej pola (publiczne i prywatne). Natomiast zmienne lub pola typów odniesień mogą zawierać null lub mogą odnosić się do obiektu przechowywanego w innym miejscu, do którego może istnieć dowolna liczba innych odniesień. Pola struktury będą przechowywane w tym samym miejscu co zmienna lub pole tego typu struktury, które może znajdować się na stosie lub może być częścią kolejny obiekt sterty.

Utworzenie zmiennej lub pola typu primitive value utworzy je z wartością domyślną; utworzenie zmiennej lub pola typu structure utworzy nową instancję, tworząc w niej wszystkie pola w sposób domyślny. Tworzenie nowej instancji typu referencyjnego rozpocznie się od utworzenia wszystkich pól w niej w sposób domyślny, a następnie uruchomienia opcjonalnego dodatkowego kodu w zależności od typu.

Kopiowanie jednej zmiennej lub pola prymitywnego typ do innego skopiuje wartość. Skopiowanie jednej zmiennej lub pola typu struktura do innej spowoduje skopiowanie wszystkich pól (publicznych i prywatnych) pierwszej instancji do drugiej instancji. Skopiowanie jednej zmiennej lub pola typu reference do innej spowoduje, że ta ostatnia będzie odnosić się do tej samej instancji co pierwsza (jeśli istnieje).

Należy zauważyć, że w niektórych językach, takich jak C++, zachowanie semantyczne typu jest niezależne od sposobu jego przechowywania, ale nie jest to prawdą w przypadku .NET. jeśli Typ implementuje semantykę mutowalnych wartości, kopiowanie jednej zmiennej tego typu do innej kopiuje właściwości first do innej instancji, o której mowa w second, a użycie członka second do mutacji spowoduje zmianę drugiej instancji, ale nie pierwszej. Jeśli typ implementuje zmienną semantykę odniesienia, skopiowanie jednej zmiennej do drugiej i użycie elementu second do mutacji obiektu wpłynie na obiekt, do którego odnosi się pierwsza zmienna; typy z immutable semantyka nie pozwala na mutację, więc nie ma znaczenia semantycznie, czy kopiowanie tworzy nową instancję, czy tworzy kolejne odniesienie do pierwszej.

W. NET, typy wartości mogą zaimplementować dowolną z powyższych semantyki, pod warunkiem, że wszystkie ich pola mogą to zrobić. Typ odniesienia może jednak implementować tylko zmienną semantykę odniesienia lub semantykę niezmienną; typy wartości z polami zmiennych typów odniesienia są ograniczone do implementacji zmiennego odniesienia semantyka lub dziwna semantyka hybrydowa.

 1
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
2015-04-06 11:54:00