Domanda

Qual è la differenza tra struttura e classe in .NET?

È stato utile?

Soluzione

In .NET esistono due categorie di tipi, tipi di riferimento E tipi di valore.

Le strutture sono tipi di valore e le classi lo sono tipi di riferimento.

La differenza generale è che a tipologia di riferimento vive sul mucchio, e a tipo di valore vive in linea, ovvero ovunque sia definita la variabile o il campo.

Una variabile contenente a tipo di valore contiene l'intero tipo di valore valore.Per una struttura, ciò significa che la variabile contiene l'intera struttura, con tutti i suoi campi.

Una variabile contenente a tipologia di riferimento contiene un puntatore o a riferimento da qualche altra parte nella memoria dove risiede il valore effettivo.

Questo ha un vantaggio, per cominciare:

  • tipi di valore contiene sempre un valore
  • tipi di riferimento può contenere a nullo-riferimento, nel senso che al momento non si riferiscono a nulla

Internamente, tipologia di riferimentosono implementati come puntatori e, sapendolo, e sapendo come funziona l'assegnazione delle variabili, ci sono altri modelli comportamentali:

  • copiare il contenuto di a tipo di valore variabile in un'altra variabile, copia l'intero contenuto nella nuova variabile, rendendo i due distinti.In altre parole, dopo la copia, le modifiche apportate a uno non influenzeranno l'altro
  • copiare il contenuto di a tipologia di riferimento variabile in un'altra variabile, copia il riferimento, il che significa che ora hai due riferimenti alla stessa altrove memorizzazione dei dati effettivi.In altre parole, dopo la copia, la modifica dei dati in un riferimento sembrerà influenzare anche l'altro, ma solo perché in realtà stai guardando gli stessi dati in entrambi i posti

Quando dichiari variabili o campi, ecco come differiscono i due tipi:

  • variabile: tipo di valore vive sulla pila, tipologia di riferimento vive nello stack come puntatore a qualche punto nella memoria heap dove risiede la memoria effettiva (anche se nota Serie di articoli di Eric Lipperts:Lo stack è un dettaglio di implementazione.)
  • campo classe/struttura: tipo di valore vive completamente all'interno del tipo, tipologia di riferimento vive all'interno del tipo come puntatore a qualche punto della memoria heap in cui risiede la memoria effettiva.

Altri suggerimenti

Un breve riepilogo di ciascuno:

Solo classi:

  • Può supportare l'ereditarietà
  • Sono tipi di riferimento (puntatore).
  • Il riferimento può essere nullo
  • Hanno un sovraccarico di memoria per ogni nuova istanza

Solo strutture:

  • Non supporta l'ereditarietà
  • Sono tipi di valore
  • Vengono passati per valore (come i numeri interi)
  • Non può avere un riferimento nullo (a meno che non venga utilizzato Nullable)
  • Non hanno un sovraccarico di memoria per nuova istanza, a meno che non siano "boxed"

Sia classi che strutture:

  • Sono tipi di dati composti generalmente utilizzati per contenere alcune variabili che hanno qualche relazione logica
  • Può contenere metodi ed eventi
  • Può supportare le interfacce

In .NET le dichiarazioni di struttura e classe distinguono tra tipi di riferimento e tipi di valore.

Quando si passa un tipo di riferimento, ne viene effettivamente memorizzato solo uno.Tutto il codice che accede all'istanza accede alla stessa.

Quando passi un tipo di valore, ognuno è una copia.Tutto il codice funziona sulla propria copia.

Questo può essere mostrato con un esempio:

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.

Per una classe questo sarebbe diverso

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.

Le classi non possono essere nulla: il riferimento può puntare a un valore nullo.

Le strutture rappresentano il valore effettivo: possono essere vuote ma mai nulle.Per questo motivo le strutture hanno sempre un costruttore predefinito senza parametri: necessitano di un "valore iniziale".

Da Microsoft Scelta tra classe e struttura ...

Come regola generale, la maggior parte dei tipi in un quadro dovrebbe essere le classi.Esistono, tuttavia, alcune situazioni in cui le caratteristiche di un tipo di valore rendono più appropriato utilizzare le strutture.

CONSIDERARE una struttura invece di una classe:

  • Se le istanze del tipo sono piccole e comunemente di breve durata o sono comunemente incorporate in altri oggetti.

X EVITARE una struttura a meno che il tipo non lo abbia Tutto Delle seguenti caratteristiche:

  • Rappresenta logicamente un singolo valore, simile ai tipi primitivi (int, double, ecc.).
  • Ha una dimensione di istanza inferiore a 16 byte.
  • È immutabile. (non può essere modificato)
  • Non dovrà essere inscatolato frequentemente.

Oltre a tutte le differenze descritte nelle altre risposte:

  1. Strutture non può avere un costruttore esplicito senza parametri mentre una classe può
  2. Strutture non può avere distruttori, mentre una classe può
  3. Strutture non può ereditare da un'altra struttura o classe mentre una classe può ereditare da un'altra classe.(Sia le strutture che le classi possono essere implementate da un'interfaccia.)

Se stai cercando un video che spieghi tutte le differenze, puoi dare un'occhiata Parte 29 - Tutorial su C# - Differenza tra classi e strutture in C#.

Le istanze delle classi vengono archiviate nell'heap gestito.Tutte le variabili che "contengono" un'istanza sono semplicemente un riferimento all'istanza nell'heap.Il passaggio di un oggetto a un metodo comporta il passaggio di una copia del riferimento, non dell'oggetto stesso.

Le strutture (tecnicamente, i tipi valore) vengono archiviate ovunque vengano utilizzate, proprio come un tipo primitivo.I contenuti possono essere copiati dal runtime in qualsiasi momento e senza invocare un costruttore di copia personalizzato.Il passaggio di un tipo di valore a un metodo implica la copia dell'intero valore, ancora una volta senza richiamare alcun codice personalizzabile.

La distinzione è resa migliore dai nomi C++/CLI:"ref class" è una classe come descritta per prima, "value class" è una classe come descritta per seconda.Le parole chiave "class" e "struct" utilizzate da C# sono semplicemente qualcosa che deve essere appreso.

Differenza tra strutture e classi:

  • Le strutture sono di tipo valore mentre Le classi sono di tipo di riferimento.
  • Le strutture vengono archiviate nello stack mentre Le lezioni sono archiviate sul mucchio.
  • I tipi di valore mantengono il loro valore in memoria in cui sono dichiarati, ma il tipo di riferimento contiene un riferimento a una memoria dell'oggetto.
  • Tipi di valore distrutti immediatamente Dopo che l'ambito è stato perso mentre il tipo di riferimento solo la variabile si distrugge dopo la perdita dell'ambito.L'oggetto viene successivamente distrutto dal collezionista della spazzatura.
  • Quando si copia la struttura in un'altra struttura, una nuova copia di quella struttura viene creata modificata di una struttura non influirà sul valore dell'altra struttura.
  • Quando si copia una classe in un'altra classe, copia solo la variabile di riferimento.
  • Entrambe le variabili di riferimento puntano allo stesso oggetto nell'heap.La modifica a una variabile influenzerà l'altra variabile di riferimento.
  • Le strutture non possono avere distruttori, ma le classi possono avere distruttori.
  • Le strutture non possono avere costruttori espliciti senza parametri Mentre una classe può strutture non supporta l'eredità, ma le classi lo fanno.Entrambi supportano l'eredità da un'interfaccia.
  • Le strutture sono di tipo sigillato.

Struttura vs classe

Una struttura è un tipo di valore, quindi viene archiviata nello stack, ma una classe è un tipo di riferimento e viene archiviata nell'heap.

Una struttura non supporta l'ereditarietà e il polimorfismo, ma una classe li supporta entrambi.

Per impostazione predefinita, tutti i membri della struttura sono pubblici, ma i membri della classe sono privati ​​per impostazione predefinita.

Poiché una struttura è un tipo valore, non possiamo assegnare null a un oggetto struct, ma non è il caso di una classe.

Giusto per completarlo, c'è un'altra differenza quando si utilizza il file Equals metodo, che viene ereditato da tutte le classi e strutture.

Diciamo che abbiamo una classe e una struttura:

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

e nel metodo Main abbiamo 4 oggetti.

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;
}

Poi:

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

COSÌ, le strutture sono adatte per oggetti di tipo numerico, come i punti (salvare le coordinate xey).E le lezioni sono adatte per gli altri.Anche se 2 persone hanno lo stesso nome, altezza, peso..., sono pur sempre 2 persone.

In aggiunta alle altre risposte, c'è una differenza fondamentale che vale la pena notare, ed è il modo in cui viene archiviata in memoria.Ciò può avere un effetto notevole sulle prestazioni degli array.Le strutture sono tipi di valore, quindi memorizzano un valore nell'area di memoria a cui puntano, le classi sono tipi di riferimento, quindi fanno riferimento a una classe nell'area di memoria a cui puntano, il valore effettivo viene archiviato altrove.

  • Con una struttura, la memoria viene allocata all'interno della classe contenitore per archiviare i dati.
  • Con una classe, la classe che la contiene conterrà semplicemente un puntatore alla nuova classe in un'area diversa della memoria.

Questo vale anche per gli array, quindi un array di strutture in memoria ha questo aspetto

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

Dove un array di classi assomiglia a questo

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

I valori effettivi che ti interessano non vengono effettivamente archiviati nell'array, ma altrove nella memoria.

Per la stragrande maggioranza delle applicazioni questa differenza non ha molta importanza, tuttavia, nel codice ad alte prestazioni ciò influirà sulla posizione dei dati all'interno della memoria e avrà un grande impatto sulle prestazioni della cache della CPU.L'uso delle classi quando avresti potuto/dovuto utilizzare le strutture aumenterà enormemente il numero di errori di cache sulla CPU.

La cosa più lenta che fa una CPU moderna non è elaborare i numeri, ma recuperare i dati dalla memoria e un colpo alla cache L1 è molte volte più veloce della lettura dei dati dalla RAM.

Bene, per cominciare, una struttura viene passata per valore anziché per riferimento.Le strutture sono adatte per strutture dati relativamente semplici, mentre le classi hanno molta più flessibilità da un punto di vista architettonico tramite polimorfismo ed ereditarietà.

Altri probabilmente possono darti più dettagli di me, ma utilizzo le strutture quando la struttura che sto cercando è semplice.

Oltre alla differenza fondamentale dello specificatore di accesso e ai pochi menzionati sopra, vorrei aggiungere alcune delle differenze principali, inclusi alcuni dei menzionati sopra, con un esempio di codice con output, che darà un'idea più chiara del riferimento e del valore

Strutture:

  • Sono tipi di valore e non richiedono l'allocazione dell'heap.
  • L'allocazione della memoria è diversa e viene archiviata nello stack
  • Utile per piccole strutture dati
  • Influiscono sulle prestazioni, quando passiamo il valore al metodo, passiamo l'intera struttura dei dati e tutto viene passato allo stack.
  • Il costruttore restituisce semplicemente il valore della struttura stesso (tipicamente in una posizione temporanea nello stack) e questo valore viene quindi copiato secondo necessità
  • Ciascuna variabile ha la propria copia dei dati e non è possibile che le operazioni su una influenzino l'altra.
  • Non supportano l'ereditarietà specificata dall'utente ed ereditano implicitamente dal tipo oggetto

Classe:

  • Valore del tipo di riferimento
  • Memorizzato nell'heap
  • Memorizza un riferimento a un oggetto allocato dinamicamente
  • I costruttori vengono richiamati con l'operatore new, ma ciò non alloca memoria nell'heap
  • Più variabili possono avere un riferimento allo stesso oggetto
  • È possibile che le operazioni su una variabile influenzino l'oggetto a cui fa riferimento l'altra variabile

Esempio di codice

    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;
        }
    }

Produzione

Il valore iniziale dell'oggetto struct è:10

Metodo struct all'interno del metodo all'interno del metodo dell'oggetto struct è:20

Dopo la chiamata del metodo, il valore dell'oggetto struct è:10

Il valore iniziale dell'oggetto classe è:10

Metodo della classe all'interno del valore del metodo dell'oggetto Classe è:20

Dopo che il valore della chiamata al metodo dell'oggetto classe è:20

Qui puoi vedere chiaramente la differenza tra chiamata per valore e chiamata per riferimento.

  1. Gli eventi dichiarati in una classe hanno il loro accesso += e -= automaticamente bloccato tramite un lucchetto (questo) per renderli thread-safe (gli eventi statici sono bloccati sul tipo della classe).Gli eventi dichiarati in una struttura non hanno i loro accessi += e -= bloccati automaticamente.Un lock(this) per una struttura non funzionerebbe poiché puoi bloccare solo un'espressione di tipo riferimento.

  2. La creazione di un'istanza di struttura non può causare una Garbage Collection (a meno che il costruttore non crei direttamente o indirettamente un'istanza del tipo di riferimento) mentre la creazione di un'istanza del tipo di riferimento può causare la Garbage Collection.

  3. Una struttura ha sempre un costruttore predefinito pubblico incorporato.

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

    Ciò significa che una struttura è sempre istanziabile mentre una classe potrebbe non esserlo poiché tutti i suoi costruttori potrebbero essere privati.

    class NonInstantiable
    {
        private NonInstantiable() // OK
        {
        }
    }
    
    struct Direct
    {
        private Direct() // Compile-time error
        {
        }
    }
    
  4. Una struttura non può avere un distruttore.Un distruttore è semplicemente una sostituzione di object.Finalize sotto mentite spoglie e le strutture, essendo tipi di valore, non sono soggette alla garbage collection.

    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. Una struttura è implicitamente sigillata, una classe no.
    Una struttura non può essere astratta, una classe sì.
    Una struttura non può chiamare:base() nel suo costruttore mentre una classe senza classe base esplicita può farlo.
    Una struttura non può estendere un'altra classe, una classe sì.
    Una struttura non può dichiarare membri protetti (ad esempio campi, tipi annidati), a differenza di una classe.
    Una struttura non può dichiarare membri di funzioni astratte, una classe astratta sì.
    Una struttura non può dichiarare membri di funzioni virtuali, una classe sì.
    Una struttura non può dichiarare membri di funzioni sigillate, una classe sì.
    Una struttura non può dichiarare membri della funzione di override, una classe sì.
    L'unica eccezione a questa regola è che una struttura può sovrascrivere i metodi virtuali di System.Object, vale a dire, Equals(), GetHashCode() e ToString().

Come precedentemente menzionato:Le classi sono tipi di riferimento mentre le strutture sono tipi di valore con tutte le conseguenze.

Come regola generale, le Linee guida per la progettazione di Framework consigliano di utilizzare Structs anziché classi se:

  • Ha una dimensione di istanza inferiore a 16 byte
  • Rappresenta logicamente un singolo valore, simile ai tipi primitivi (int, double, ecc.)
  • È immutabile
  • Non dovrà essere inscatolato frequentemente
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|                       |                                                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                                                                        |
| Access Modifiers      | public, private, internal                                                                            | public, protected, internal, protected internal, private protected                                |
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+

Le strutture rappresentano il valore effettivo: possono essere vuote ma mai nulle

Questo è vero, tuttavia si noti anche che a partire da .NET 2 le strutture supportano una versione Nullable e C# fornisce dello zucchero sintattico per facilitarne l'utilizzo.

int? value = null;
value  = 1;

C'è un caso interessante di puzzle "classe vs struttura" - situazione in cui è necessario restituire diversi risultati dal metodo:scegli quale utilizzare.Se conosci la storia di ValueTuple, sai che ValueTuple (struct) è stato aggiunto perché dovrebbe essere più efficace di Tuple (class).Ma cosa significa in numeri?Due prove:uno è struct/class che ha 2 campi, l'altro con struct/class che ha 8 campi (con dimensione superiore a 4 - la classe dovrebbe diventare più efficace della struttura in termini di tick del processore, ma ovviamente dovrebbe essere considerato anche il carico GC).

PSUn altro punto di riferimento per il caso specifico "sturct o classe con raccolte" è presente: 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 |

Prova del codice:

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;
            }
        }
    }
}

Ogni variabile o campo di un tipo di valore o di struttura primitivo contiene un'istanza univoca di quel tipo, inclusi tutti i suoi campi (pubblici e privati).Al contrario, le variabili o i campi dei tipi di riferimento possono contenere null o possono fare riferimento a un oggetto, archiviato altrove, a cui possono esistere anche un numero qualsiasi di altri riferimenti.I campi di una struttura verranno archiviati nello stesso posto della variabile o del campo di quel tipo di struttura, che può essere nello stack o essere parte di un altro oggetto heap.

La creazione di una variabile o di un campo con un tipo di valore primitivo lo creerà con un valore predefinito;la creazione di una variabile o di un campo di tipo struttura creerà una nuova istanza, creando tutti i campi al suo interno nella modalità predefinita.Creandone uno nuovo esempio di un tipo di riferimento inizierà creando tutti i campi al suo interno nel modo predefinito e quindi eseguendo codice aggiuntivo facoltativo a seconda del tipo.

La copia di una variabile o di un campo di tipo primitivo in un altro ne copierà il valore.La copia di una variabile o di un campo di tipo struttura in un altro copierà tutti i campi (pubblici e privati) della prima istanza nella seconda istanza.La copia di una variabile o di un tipo di campo di riferimento in un altro farà sì che quest'ultimo faccia riferimento alla stessa istanza del primo (se presente).

È importante notare che in alcuni linguaggi come C++ il comportamento semantico di un tipo è indipendente dal modo in cui viene archiviato, ma ciò non è vero per .NET.Se un tipo implementa la semantica dei valori mutabili, copiare una variabile di quel tipo in un'altra copia le proprietà della prima in un'altra istanza, a cui fa riferimento la seconda, e l'utilizzo di un membro della seconda per mutarla causerà la modifica della seconda istanza , ma non il primo.Se un tipo implementa una semantica di riferimento mutabile, la copia di una variabile in un'altra e l'utilizzo di un membro della seconda per modificare l'oggetto influenzeranno l'oggetto a cui fa riferimento la prima variabile;i tipi con semantica immutabile non consentono la mutazione, quindi non importa semanticamente se la copia crea una nuova istanza o crea un altro riferimento alla prima.

In .NET è possibile che i tipi valore implementino una qualsiasi delle semantiche precedenti, a condizione che tutti i relativi campi possano fare altrettanto.Un tipo di riferimento, tuttavia, può implementare solo la semantica di riferimento mutabile o la semantica immutabile;i tipi di valore con campi di tipi di riferimento mutabili sono limitati all'implementazione della semantica di riferimento mutabile o della semantica ibrida strana.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top