Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Una definizione di classe o struct è simile a un progetto che specifica le operazioni che il tipo può eseguire. Un oggetto è fondamentalmente un blocco di memoria allocato e configurato in base al progetto. Un programma potrebbe creare molti oggetti della stessa classe. Gli oggetti sono detti anche istanze e possono essere archiviati in una variabile denominata o in una matrice o in una raccolta. Il codice client è il codice che usa queste variabili per chiamare i metodi e accedere alle proprietà pubbliche dell'oggetto. In un linguaggio orientato agli oggetti, ad esempio C#, un programma tipico è costituito da più oggetti che interagiscono dinamicamente.
Nota
I tipi statici si comportano in modo diverso rispetto a quanto descritto qui. Per altre informazioni, vedere Classi statiche e membri di classi statiche.
Istanze di struct vs. istanze di classe
Poiché le classi sono tipi riferimento, una variabile di un oggetto classe contiene un riferimento all'indirizzo dell'oggetto nell'heap gestito. Se alla prima variabile viene assegnata una seconda variabile dello stesso tipo, entrambe le variabili fanno riferimento all'oggetto in tale indirizzo. Questo punto viene illustrato in modo più dettagliato più avanti in questo articolo.
Le istanze delle classi vengono create usando l'operatorenew . Nell'esempio seguente, Person è il tipo e person1 sono person2 istanze, o oggetti, di tale tipo.
using System;
public class Person(string name, int age)
{
public string Name { get; set; } = name;
public int Age { get; set; } = age;
// Other properties, methods, events...
}
class Program
{
static void Main()
{
Person person1 = new("Leopold", 6);
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
// Declare new person, assign person1 to it.
Person person2 = person1;
// Change the name of person2, and person1 also changes.
person2.Name = "Molly";
person2.Age = 16;
Console.WriteLine($"person2 Name = {person2.Name} Age = {person2.Age}");
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
/*
Output:
person1 Name = Leopold Age = 6
person2 Name = Molly Age = 16
person1 Name = Molly Age = 16
*/
}
}
Poiché gli struct sono tipi valore, una variabile di un oggetto struct contiene una copia dell'intero oggetto. È anche possibile creare istanze di struct usando l'operatore new , ma questa operazione non è necessaria, come illustrato nell'esempio seguente:
using System;
namespace Example
{
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
public class Application
{
static void Main()
{
// Create struct instance and initialize by using "new".
// Memory is allocated on thread stack.
Person p1 = new("Alex", 9);
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
// Create new struct object. Note that struct can be initialized
// without using "new".
Person p2 = p1;
// Assign values to p2 members.
p2.Name = "Spencer";
p2.Age = 7;
Console.WriteLine($"p2 Name = {p2.Name} Age = {p2.Age}");
// p1 values remain unchanged because p2 is copy.
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
}
}
/*
Output:
p1 Name = Alex Age = 9
p2 Name = Spencer Age = 7
p1 Name = Alex Age = 9
*/
}
La memoria per entrambi p1 e p2 viene allocata nello stack del thread. Tale memoria viene recuperata insieme al tipo o al metodo in cui è dichiarato. Questo è un motivo per cui le strutture vengono copiate in fase di assegnazione. Al contrario, la memoria allocata per un'istanza di classe viene recuperata automaticamente (Garbage Collection) da Common Language Runtime quando tutti i riferimenti all'oggetto non rientrano nell'ambito. Non è possibile eliminare in modo deterministico un oggetto classe come in C++. Per altre informazioni su Garbage Collection in .NET, vedere Garbage Collection.
Nota
L'allocazione e la deallocazione della memoria nell'heap gestito sono altamente ottimizzate in Common Language Runtime. Nella maggior parte dei casi, non esiste alcuna differenza significativa nel costo delle prestazioni dell'allocazione di un'istanza di classe nell'heap rispetto all'allocazione di un'istanza di struct nello stack.
Identità dell'oggetto e uguaglianza dei valori
Quando si confrontano due oggetti per verificarne l'uguaglianza, è necessario innanzitutto stabilire se le due variabili rappresentano lo stesso oggetto in memoria o se i valori di uno o più campi sono equivalenti. Se si intende confrontare i valori, è necessario valutare se gli oggetti sono istanze di tipi valore (struct) o tipi di riferimento (classi, delegati, matrici).
Per determinare se due istanze di classe fanno riferimento alla stessa posizione in memoria (ovvero hanno la stessa identità), usare il metodo statico Object.ReferenceEquals . (System.Object è la classe base implicita per tutti i tipi valore e i tipi riferimento, inclusi gli struct e le classi definiti dall'utente.
Il ValueType.Equals metodo, per impostazione predefinita, determina se i campi dell'istanza in due istanze dello struct hanno gli stessi valori. Poiché tutti gli struct ereditano in modo implicito da System.ValueType, puoi chiamare il metodo direttamente sul proprio oggetto, come illustrato nell'esempio seguente.
// Person is defined in the previous example. //public struct Person(string name, int age) //{ // public string Name { get; set; } = name; // public int Age { get; set; } = age; //} Person p1 = new("Wallace", 75); Person p2 = new("", 42); p2.Name = "Wallace"; p2.Age = 75; if (p2.Equals(p1)) Console.WriteLine("p2 and p1 have the same values."); // Output: p2 and p1 have the same values.L'implementazione predefinita System.ValueType di
Equalsutilizza il boxing e reflection in alcuni casi. Per informazioni su come fornire un algoritmo di uguaglianza efficiente specifico del tipo, vedere Come definire l'uguaglianza dei valori per un tipo. I record sono tipi di riferimento che usano la semantica del valore per l'uguaglianza.Per determinare se i valori dei campi in due istanze di classe sono uguali, è possibile usare il Equals metodo o l'operatore == . Tuttavia, usarli solo se la classe ha eseguito l'override o li ha sottoposti a overload per fornire una definizione personalizzata del significato di "uguaglianza" per gli oggetti di tale tipo. La classe potrebbe anche implementare l'interfaccia IEquatable<T> o l'interfaccia IEqualityComparer<T> . Entrambe le interfacce forniscono metodi che possono essere usati per testare l'uguaglianza dei valori. Quando si progettano classi personalizzate che sovrascrivono
Equals, è importante seguire le linee guida indicate in Come definire l'uguaglianza dei valori per un tipo e Object.Equals(Object).
Sezioni correlate
Per altre informazioni: