Freigeben über


Objekte – Erstellen von Instanzen von Typen

Eine Klassen- oder Strukturdefinition ist wie eine Blaupause, die angibt, was der Typ tun kann. Ein Objekt ist im Grunde ein Speicherblock, der gemäß dem Blueprint zugeordnet und konfiguriert wurde. Ein Programm kann viele Objekte derselben Klasse erstellen. Objekte werden auch als Instanzen bezeichnet, und sie können entweder in einer benannten Variablen oder in einer Matrix oder Auflistung gespeichert werden. Clientcode ist der Code, der diese Variablen verwendet, um die Methoden aufzurufen und auf die öffentlichen Eigenschaften des Objekts zuzugreifen. In einer objektorientierten Sprache wie C# besteht ein typisches Programm aus mehreren Objekten, die dynamisch interagieren.

Hinweis

Statische Typen verhalten sich anders als hier beschrieben. Weitere Informationen finden Sie unter "Static Classes" und "Static Class Members".

Strukturinstanzen im Vergleich zu Klasseninstanzen

Da Klassen Referenztypen sind, enthält eine Variable eines Klassenobjekts einen Verweis auf die Adresse des Objekts im verwalteten Heap. Wenn der ersten Variablen eine zweite Variable desselben Typs zugewiesen ist, verweisen beide Variablen auf das Objekt an dieser Adresse. Dieser Punkt wird weiter unten in diesem Artikel ausführlicher erläutert.

Instanzen von Klassen werden mithilfe des new Operators erstellt. Im folgenden Beispiel Person handelt es sich um den Typ und person1person2 sind Instanzen oder Objekte dieses Typs.

using System;

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 = {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
*/

Da Strukturen Werttypen sind, enthält eine Variable eines Strukturobjekts eine Kopie des gesamten Objekts. Instanzen von Strukturen können auch mithilfe des new Operators erstellt werden, dies ist jedoch nicht erforderlich, wie im folgenden Beispiel gezeigt:

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 Person("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
    */
}

Der Arbeitsspeicher für beide p1 und p2 wird im Threadstapel zugewiesen. Dieser Speicher wird zusammen mit dem Typ oder der Methode, in dem er deklariert wird, erneut beansprucht. Dies ist ein Grund, weshalb Strukturen bei Zuweisung kopiert werden. Im Gegensatz dazu wird der Speicher, der für eine Klasseninstanz zugeordnet ist, automatisch von der Common Language Runtime freigegeben (von Garbage Collection bereinigt), wenn alle Verweise auf das Objekt außerhalb des Gültigkeitsbereichs liegen. Es ist nicht möglich, ein Klassenobjekt wie in C++ deterministisch zu zerstören. Weitere Informationen zur Garbage Collection in .NET finden Sie unter Garbage Collection.

Hinweis

Die Belegung und Freigabe von Arbeitsspeicher auf dem verwalteten Heap ist in der Common Language Runtime stark optimiert. In den meisten Fällen besteht kein signifikanter Unterschied im Leistungsaufwand beim Zuweisen einer Klasseninstanz auf dem Heap im Vergleich zur Zuweisung einer Strukturinstanz auf dem Stack.

Objektidentität im Vergleich zur Wertgleichstellung

Wenn Sie zwei Objekte mit Gleichheit vergleichen, müssen Sie zuerst unterscheiden, ob die beiden Variablen dasselbe Objekt im Arbeitsspeicher darstellen oder ob die Werte eines oder mehrerer felder gleichwertig sind. Wenn Sie Werte vergleichen möchten, müssen Sie überlegen, ob es sich bei den Objekten um Instanzen von Werttypen (Strukturen) oder Referenztypen (Klassen, Stellvertretungen, Arrays) handelt.

  • Verwenden Sie die statische Methode, um zu ermitteln, ob zwei Klasseninstanzen auf denselben Speicherort im Speicher verweisen (was bedeutet, dass sie dieselbe Object.Equals haben). (System.Object ist die implizite Basisklasse für alle Werttypen und Verweistypen, einschließlich benutzerdefinierter Strukturen und Klassen.)

  • Verwenden Sie die ValueType.Equals Methode, um zu bestimmen, ob die Instanzfelder in zwei Strukturinstanzen dieselben Werte aufweisen. Da alle Strukturen implizit von System.ValueType erben, rufen Sie die Methode direkt auf Ihrem Objekt auf, wie im folgenden Beispiel gezeigt:

    // Person is defined in the previous example.
    
    //public struct Person
    //{
    //    public string Name;
    //    public int Age;
    //    public Person(string name, int age)
    //    {
    //        Name = name;
    //        Age = age;
    //    }
    //}
    
    Person p1 = new Person("Wallace", 75);
    Person p2 = new Person("", 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.
    

    Die System.ValueType-Implementierung von Equals verwendet in einigen Fällen Boxing und Reflexion. Informationen zum Bereitstellen eines effizienten Gleichheitsalgorithmus, der für Ihren Typ spezifisch ist, finden Sie unter How to define value equality for a type. Datensätze sind Referenztypen, die Wertsemantik für Gleichheit verwenden.

  • Um zu ermitteln, ob die Werte der Felder in zwei Klasseninstanzen gleich sind, können Sie die Methode oder den Equals verwenden. Verwenden Sie sie jedoch nur, wenn die Klasse die Werte überschrieben oder überladen hat, um eine benutzerdefinierte Definition von „Gleichheit“ für Objekte dieses Typs bereitzustellen. Die Klasse kann auch die IEquatable<T> Schnittstelle oder die IEqualityComparer<T> Schnittstelle implementieren. Beide Schnittstellen stellen Methoden bereit, die zum Testen der Wertgleichstellung verwendet werden können. Achten Sie beim Entwerfen Ihrer eigenen Klassen, die Equals überschreiben, unbedingt auf die Richtlinien in Wie man Wertgleichheit für einen Typ definiert und Object.Equals(Object).

Weitere Informationen: