C# Objekt Initialisierung?

5 Antworten

Um ein Objekt einer Klasse zu erstellen, benötigst du stets den new-Operator, gefolgt von einem Konstruktoraufruf. Der new-Operator reserviert den Speicher, der Konstruktor initialisiert das Objekt.

Beispiel:

class Car
{
  public Car()
  {
  }

  public Car(Color color)
  {
    // ...
  }
}

// Main:
new Car();
new Car(Color.RED);

Im Beispiel werden zwei Car-Objekte angelegt, jeweils mit einer anderen Konstruktorüberladung. Anders als in deinem Beispiel werden dabei keine Variablen angelegt, die dann auf diese Objekte verweisen. Das könntest du aber tun, wenn du mit den Objekten weiter arbeiten möchtest.

Nur um ein Objekt anzulegen, bedarf es keiner Variable, die auf das Objekt zeigt. Wenn das Objekt aber auch keinen Nutzen hat (also so wie die beiden Car-Objekte von oben nur vor sich herdümpeln würde), wird es vom Garbage Collector ziemlich schnell wieder vom Speicher geräumt.

Wenn du ein Objekt anlegst und es in einer Variable speichern möchtest, muss der Typ auf der linken Seite nicht zwingend dem konkreten Typnamen des Objekts entsprechen. Es gibt einmal die Möglichkeit der Typinterferenz:

var myObj = new Car();

bei der der Compiler den passenden Typ für die Variable selbstständig (mit Hilfe des rechten Ausdrucks) ableitet oder man schiebt das Objekt in einen Basistyp:

class Vehicle
{
}

class Car : Vehicle
{
}

// Main:
Vehicle car = new Car();

Dies setzt allerdings voraus, dass es diesen Basistyp auch gibt. Im Detail erfährst du mehr darüber, wenn du dich mit Vererbung und Polymorphie auseinandersetzt.

"Car" ist der Name der Klasse.
"new" sagt, dass ein neues Objekt von der klasse erstellt werden soll.
Die Klammern sagen aus, dass der Konstruktor der Klasse keine Parameter braucht.
"myObj" ist der Name der Variable, die auf das erstellte Objekt zeigt.

Eine Variable ist kein Objekt. Technisch ist die Variable nur ein Name für einen Wert auf dem Stack (ein Stück speziell organisierter RAM, in dem die Methode arbeitet). Bei einem Objekt ist dieser eine Wert die Adresse im Heap (der Rest vom RAM und unorganisiert), wo das Objekt wirklich gespeichert wird. Diese Adresse ändert sich aber ständig, das macht die Runtime im Hintergrund, um Speicherbedarf und Performance zu optimieren. Außerdem hört es mit dem einen Stück Heap nicht auf, wenn das Objekt noch andere Objekte enthält, enthält es wieder nur eine Adresse zum Heap.

Anders ticken da die Structs, eine Struct-Instanz wird zwar genauso erstellt, wie die einer Klasse, doch hier gibt es weit weniger "Drumherum", wie bei Klassen. Das bietet viele Optimierungsmöglichkeiten, macht die Sache aber auch komplizierter. Z.B. liegt bei einem Struct nicht nur die Adresse auf dem Stack, sondern direkt das ganze Objekt und da Structs keine Vererbung unterstützen, fällt der ganze dafür notwendige Overhead auch weg.

Muss man den Klassen-Namen immer zweimal schreiben, einmal vor dem '=' und einmal danach?

Nein, es reicht einmal.
Das sind drei mögliche Schreibweisen, alles erlaubt:

Car myObj = new Car();
var myObj = new Car();
Car myObj = new();

Immer wenn der zweite Typ eindeutig feststehen kann, kann man es weg lassen.

Woher ich das weiß:Berufserfahrung

Car myObj; ist die Definition einer Variable vom Typ Car.

myObj = new Car() erstellt jetzt ein Objekt vom Typ Car und weißt es der Variable myObj zu. Da Classen in C# im Gegensatz zu Structs sogenannte reference types sind, wird hier theoretisch nur eine Referenz in der Variable myObj gespeichert und nicht die Instanz der Klasse selbst. Das hat zB einige Auswirkungen wenn man Klassen an Funktionen als Parameter übergibt.

Muss man den Klassen-Namen immer zweimal schreiben, einmal vor dem '=' und einmal danach?

Jein C# unterstützt ein Feature Names type deduction, wenns also aus dem Kontext klar ist welchen Typ eine Variable hat muss man ihn nicht unbedingt explizit angeben.

Man kann daher schreiben:

var myObj = new Car();

Da es aus dem Kontext klar ist dass die Variable myObj vom Typ Car ist geht das. Was nicht gehn würde wäre:

var myObj;
myObj = new Car();

Hier weiß der Compiler beim erstellen der Variable myObj nicht welchen Typ diese haben soll.

Der von Dir gegebene Ausdruck macht 2 Dinge:

  1. er erzeugt eine leere Variable vom Typ Car. Diese heißt myObj.
  2. Er erzeugt ein Objekt vom Typ Car und lässt myObj dieses Objekt referenzieren.
Bujin  09.10.2021, 13:04

Bist du sicher? In C# gibt es meines Wissens nach keine Referenzen / Pointer und der Gleichen. Oder ich verstehe deine Antwort falsch.

0
W00dp3ckr  10.10.2021, 08:11
@Bujin

Die Pointer sind sicher versteckt in dem Sinne, dass keine Pointerarithmetik möglich ist.

0

Nicht ganz richtig. Laut

var myObj = new Car()

Quelle: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator

Ich kenne den new-operator aus C++ und dort benutzt man ihn um Instanzen zu erzeugen welche wieder gelöscht werden können. Das heißt der Speicher kann zur Laufzeit des Programms wieder freigegeben werden. Das passiert bei C# automatisch wenn ich richtig verstehe, in C++ muss/kann man das selber machen.

PeterKremsner  09.10.2021, 12:57

Was ist hier nicht ganz richtig?

Sowohl

Car myObj = new Car();

als auch

var myObj = new Car();

ist die korrekte Syntax.

Man kann aber muss nicht das type deducing verwenden.

Das passiert bei C# automatisch wenn ich richtig verstehen, in C#, in C++ muss/kann man das selber machen.

Richtig C# verwendet einen sogenannten Garbage Collector C++ nicht. Mit entsprechenden Templates zB den Pointer Templates wie unique_ptr usw. ist das aber auch in C++ nicht mehr unbedingt nötig den Speicher per Hand frei zu geben, das macht dann der Compiler für einen.

1
Bujin  09.10.2021, 13:00
@PeterKremsner

Bei meiner offfiziellen Quelle steht nichts von der ersten Schreibweise. Bin aber auch kein C# Spezi. Es kann gut sein dass C# ein wenig rückwärtskompatibel zu C++ ist und deshalb keinen Fehler ausspuckt.

0
PeterKremsner  09.10.2021, 13:02
@Bujin

In C++ kannst du auch schreiben:

Car* myCar = new Car();

und

auto myCar = new Car();

das verwendet in beiden Fällen das type deduction feature des Compilers.

Natürlich sollte man in gutem C++ den Pointer dann noch ein ein entsprechendes Template verpacken aber fürs Beispiel reichts so.

C# ist nicht Rückwärtskompatibel zu C++ aber C# hat einfach nur die Grundlegende Syntax von C/C++ und Java übernommen.

0
Bujin  09.10.2021, 13:16
@PeterKremsner

Rückwärtskompatibel war das falsche Wort, ich meinte natürlich sie haben die Syntax zum Teil übernommen damit es C++ Leute einfacher haben.

auto und Car* machen aber nicht exakt das selbe. Da muss man aufpassen!

1