Condividi tramite


Oggetti (Guida per programmatori C#)

Una definizione di classe o struttura è simile a un progetto iniziale in cui vengono specificate le funzionalità del tipo. Un oggetto è essenzialmente un blocco di memoria che è stato allocato e configurato in base al progetto iniziale. Un programma può creare molti oggetti della stessa classe. Gli oggetti, definiti anche istanze, possono essere archiviati in una variabile denominata o in una matrice o insieme. Il codice client è il codice che utilizza queste variabili per chiamare i metodi e accedere alle proprietà pubbliche dell'oggetto. In un linguaggio orientato a oggetti quale C#, un tipico programma è costituito da più oggetti che interagiscono dinamicamente.

Nota

I tipi statici si comportano in modo diverso da quanto viene descritto in questo punto. Per ulteriori informazioni, vedere Classi statiche e membri di classi statiche (Guida per programmatori C#).

Differenze tra istanze di struttureIstanze di classe

Poiché le classi sono tipi di riferimento, una variabile di un oggetto classe contiene un riferimento all'indirizzo dell'oggetto sull'heap gestito. Se al primo oggetto viene assegnato un secondo oggetto dello stesso tipo, entrambe le variabili fanno riferimento all'oggetto in corrispondenza di tale indirizzo. Questo punto viene illustrato più dettagliatamente in seguito in questo argomento.

Le istanze di classi vengono create utilizzando l'operatore new. Nel seguente esempio, Person è il tipo e person1 e person 2 sono istanze, o oggetti, di tale tipo.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    //Other properties, methods, events...
}

class Program
{
    static void Main()
    {
        Person person1 = new Person("Leopold", 6);
        Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, 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 = {0} Age = {1}", person2.Name, person2.Age);
        Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();

    }
}
/*
    Output:
    person1 Name = Leopold Age = 6
    person2 Name = Molly Age = 16
    person1 Name = Molly Age = 16
*/

Poiché le strutture sono tipi di valore, una variabile di un oggetto struttura contiene una copia dell'intero oggetto. Anche le istanze di strutture possono essere create tramite l'operatore new, ma non è obbligatorio, come illustrato nell'esempio seguente:

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 Person("Alex", 9);
        Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, 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 = {0} Age = {1}", p2.Name, p2.Age);

        // p1 values remain unchanged because p2 is  copy.
        Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age);

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
  Output:
    p1 Name = Alex Age = 9
    p2 Name = Spencer Age = 7
    p1 Name = Alex Age = 9
*/

La memoria per entrambi gli oggetti p1 sia p2 viene allocata sullo stack di thread. Tale memoria viene recuperata insieme al tipo o al metodo in cui è stata dichiarata. Questo è il motivo per cui le strutture vengono copiate per assegnazione. Per contrasto, la memoria allocata per l'istanza di una classe viene recuperata automaticamente (tramite Garbage Collection) da Common Language Runtime quando tutti i riferimenti all'oggetto sono usciti dall'ambito. Non è possibile eliminare in modo deterministico un oggetto di classe come invece avviene in C++. Per ulteriori informazioni sul sistema di Garbage Collection in .NET Framework, vedere Garbage Collection.

Nota

L'allocazione e la deallocazione di memoria sull'heap gestito sono estremamente ottimizzate in Common Language Runtime. Nella maggior parte dei casi non esistono differenze significative in termini di impatto sulle prestazioni tra l'allocazione di un'istanza di classe sull'heap e l'allocazione di un'istanza di struttura sullo stack.

Identità oggetto rispetto aUguaglianza di valori

Quando si confrontano due oggetti per verificarne l'uguaglianza, è necessario innanzitutto distinguere se si desidera determinare se le due variabili rappresentano lo stesso oggetto in memoria oppure se i valori di uno o più campi sono equivalenti. Se si intende confrontare valori, è necessario considerare se gli oggetti sono istanze di tipi di valore (strutture) o di 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à), utilizzare il metodo statico Equals. System.Object è la classe di base implicita per tutti i tipi valore e i tipi riferimento, incluse strutture e classi definite dall'utente.

  • Per determinare se i campi di istanza in due istanze di strutture hanno gli stessi valori, utilizzare il metodo ValueType.Equals. Poiché tutte le strutture ereditano implicitamente da System.ValueType, il metodo viene chiamato direttamente sull'oggetto, come illustrato nell'esempio seguente:

Person p1 = new Person("Wallace", 75);
Person p2;
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 System.ValueType di Equals utilizza la reflection perché deve essere in grado di determinare i tipi di campi presenti in tutte le strutture. Quando si creano strutture, eseguire l'override del metodo Equals per fornire un algoritmo di uguaglianza efficiente specifico del tipo.

  • Per determinare se i valori dei campi in due istanze della classe sono uguali, è possibile utilizzare il metodo Equals o l'operatore ==. Tuttavia, utilizzarli solo se la classe ha eseguito il loro override o overload per fornire una definizione personalizzata di cosa significa "uguaglianza" per gli oggetti di quel tipo. È possibile anche che la classe implementi l'interfaccia IEquatable<T> dell'interfaccia IEqualityComparer<T>. Entrambe le interfacce forniscono metodi che possono essere utilizzati per verificare l'uguaglianza dei valori. Durante la progettazione di classi personalizzate che eseguono l'override di Equals, assicurarsi di seguire le linee guida stabilite in Procedura: definire l'uguaglianza di valori per un tipo (Guida per programmatori C#) e in Object.Equals(Object).

Sezioni correlate

Per ulteriori informazioni:

Vedere anche

Riferimenti

object (Riferimenti per C#)

Ereditarietà (Guida per programmatori C#)

class (Riferimenti per C#)

struct (Riferimenti per C#)

Operatore new (Riferimenti per C#)

Concetti

Guida per programmatori C#

Common Type System