Objekty – vytváření instancí typů

Definice třídy nebo struktury je jako podrobný plán, který určuje, co může typ dělat. Objekt je blok paměti, který program přiděluje a konfiguruje podle podrobného plánu. Program může vytvořit mnoho objektů stejné třídy. Objekty můžete také nazývat instancemi. Můžete je uložit do pojmenované proměnné nebo do pole nebo kolekce. Klientský kód tyto proměnné používá k volání metod a přístup k veřejným vlastnostem objektu. V objektově orientovaném jazyce, jako je C#, se typický program skládá z více objektů, které interagují dynamicky.

Poznámka:

Statické typy se chovají jinak, než je popsáno v tomto článku. Další informace naleznete v tématu Statické třídy a statičtí členové tříd.

Instance struktury vs. instance třídy

Vzhledem k tomu, že třídy jsou odkazové typy, proměnná objektu třídy obsahuje odkaz na adresu objektu ve spravované haldě. Pokud přiřadíte druhou proměnnou stejného typu první proměnné, obě proměnné odkazují na objekt na této adrese. Tento článek popisuje tento bod podrobněji později.

Instance tříd vytvoříte pomocí operátorunew. V následujícím příkladu Person je typ a person1person2 jsou instancemi nebo objekty tohoto typu.

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
        */
    }
}

Vzhledem k tomu, že struktury jsou typy hodnot, proměnná objektu struktury obsahuje kopii celého objektu. Instance struktur můžete vytvořit také pomocí operátoru new , ale nemusíte je používat, jak je znázorněno v následujícím příkladu:

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
    */
}

Zásobník vláken přiděluje paměť pro obě p1 a p2. Program uvolní tuto paměť spolu s typem nebo metodou, ve které ji deklarujete. Tato správa paměti je jedním z důvodů, proč se struktury kopírují při přiřazení. Naproti tomu modul CLR (Common Language Runtime) automaticky uvolňuje (pomocí garbage collectoru) paměť alokovanou pro instanci třídy, když všechny odkazy na objekt přestanou být v rozsahu platnosti. Objekt třídy nemůžete deterministicky zničit, jako můžete v jazyce C++. Další informace o uvolňování paměti v .NET naleznete v tématu Uvolňování paměti.

Poznámka:

Modul CLR (Common Language Runtime) vysoce optimalizuje přidělení a uvolnění paměti ve spravované haldě. Ve většině případů není žádný významný rozdíl ve výkonových nákladech na přidělení instance třídy na paměťové haldě oproti přidělení instance struktury na zásobníku.

Identita objektu vs. rovnost hodnot

Když porovnáte dva objekty pro rovnost, nejprve se rozhodněte, zda chcete zjistit, zda dvě proměnné představují stejný objekt v paměti, nebo pokud hodnoty jednoho nebo více jejich polí jsou ekvivalentní. Pokud chcete porovnat hodnoty, zvažte, jestli jsou objekty instancemi typů hodnot (struktury) nebo odkazovými typy (třídy, delegáty, pole).

  • Pomocí statické Object.ReferenceEquals metody určete, zda dvě instance třídy odkazují na stejné umístění v paměti (což znamená, že mají stejnou identitu). (System.Object je implicitní základní třída pro všechny typy hodnot a odkazové typy, včetně uživatelem definovaných struktur a tříd.)

  • Ve výchozím nastavení metoda určuje, ValueType.Equals zda pole instance ve dvou instancích struktury mají stejné hodnoty. Vzhledem k tomu, že všechny struktury implicitně dědí z System.ValueType, voláte metodu přímo na objektu, jak je znázorněno v následujícím příkladu:

    // 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.
    

    Výchozí System.ValueType implementace Equals používá boxing a reflexi v některých případech. Informace o tom, jak implementovat efektivní algoritmus pro porovnávání rovnosti, který je specifický pro daný typ, najdete v tématu Implementujte porovnávání rovnosti sami, když typ nemůže být záznamovým typem. Záznamy jsou odkazové typy, které pro rovnost používají sémantiku hodnot.

  • Chcete-li zjistit, zda jsou hodnoty polí ve dvou instancích třídy stejné, můžete být schopni použít metodu Equals nebo operátor == . Používejte je však pouze v případě, že třída tyto metody přepsala nebo přetížila, aby poskytla vlastní definici toho, co znamená „rovnost“ pro objekty tohoto typu. Třída může také implementovat IEquatable<T> rozhraní nebo IEqualityComparer<T> rozhraní. Obě rozhraní poskytují metody, které lze použít k otestování rovnosti hodnot. Při navrhování vlastních tříd, které přepisují Equals, se nezapomeňte řídit pokyny uvedenými v Implementujte rovnost sami, když typ nemůže být record a Object.Equals(Object).

Další informace najdete tady: