8 Stimmen

Ist das Anlegen von Objekten veraltet?

Ok, hier ist die Frage... ist das neue Schlüsselwort obsolet?

Betrachte in C# (und Java, glaube ich) gibt es strenge Regeln für Typen. Klassen sind Referenztypen und können nur auf dem Heap erstellt werden. POD-Typen werden auf dem Stack erstellt; wenn Sie sie auf dem Heap zuweisen möchten, müssen Sie sie in einem Objekttyp boxen. In C# sind structs die Ausnahme, sie können auf dem Stack oder dem Heap erstellt werden.

Angesichts dieser Regeln, ergibt es Sinn, dass wir immer noch das neue Schlüsselwort verwenden müssen? Würde es nicht sinnvoll sein, dass die Sprache die richtige Allokationsstrategie basierend auf dem Typ verwendet?

Zum Beispiel, müssen wir derzeit schreiben:

SomeClassType x = new SomeClassType();

anstatt

SomeClassType x = SomeClassType();

oder auch nur

SomeClassType x;

Der Compiler würde, basierend darauf, dass der erstellte Typ ein Referenztyp ist, den Speicher für x auf dem Heap allozieren.

Dies gilt für andere Sprachen wie Ruby, PHP, et al. C/C++ erlauben dem Programmierer mehr Kontrolle darüber, wo Objekte erstellt werden, daher hat es guten Grund, das neue Schlüsselwort zu erfordern.

Ist new nur ein Überbleibsel aus den 60er Jahren und unserem C-basierten Erbe?

18voto

Stan R. Punkte 14887
SomeClassType x = SomeClassType();

In diesem Fall könnte SomeClassType() eine Methode sein, die sich an anderer Stelle befindet. Wie würde der Compiler wissen, ob er diese Methode aufrufen oder eine neue Klasse erstellen soll?

SomeClassType x;

Dies ist nicht sehr nützlich, die meisten Leute deklarieren ihre Variablen auf diese Weise und füllen sie manchmal später auf, wenn sie diese benötigen. Es wäre also nicht sinnvoll, jedes Mal, wenn Sie eine Variable deklarieren, eine Instanz im Speicher zu erstellen.

16voto

Timothy Baldridge Punkte 10139

Ihre dritte Methode funktioniert nicht, da wir manchmal ein Objekt eines Typs definieren möchten und es einer Variablen eines anderen Typs zuweisen möchten. Zum Beispiel:

Stream strm = new NetworkStream();

Ich möchte einen Stream-Typ (vielleicht um ihn weiterzugeben), aber intern möchte ich einen NetworkStream-Typ haben.

Außerdem erstelle ich oft ein neues Objekt, während ich eine Methode aufrufe:

myobj.Foo(new NetworkStream());

Wenn ich es auf diese Weise mache:

myobj.Foo(NetworkStream()); 

ist das sehr verwirrend. Erstelle ich ein Objekt oder rufe ich eine Methode auf, wenn ich NetworkStream() sage?

6voto

Aaronaught Punkte 118136

Wenn Sie einfach nur SomeClassType x; schreiben könnten und es automatisch initialisiert würde, würde das nicht für Konstruktoren mit Parametern erlauben. Nicht jede SomeClassType wird einen parameterlosen Konstruktor haben; wie würde der Compiler wissen, welche Argumente geliefert werden sollen?

public class Repository
{
    private IDbConnection connection;

    public Repository(IDbConnection connection)
    {
        if (connection == null)
        {
            throw new ArgumentNullException("connection");
        }
        this.connection = connection;
    }
}

Wie würden Sie dieses Objekt mit nur Repository rep; instanziieren? Es erfordert ein abhängiges Objekt, um ordnungsgemäß zu funktionieren.

Nicht zu erwähnen, Sie könnten möglicherweise Code wie folgt schreiben:

Dictionary instances = GetInstancesFromSomewhere();
SomeClass instance;
if (instances.TryGetValue(1, out instance))
{
    // Do something
}

Würden Sie wirklich wollen, dass es für Sie automatisch initialisiert wird?

Wenn Sie einfach nur SomeClassType x = SomeClassType() schreiben würden, dann gibt es keinen Unterschied zwischen einem Konstruktor und einer Methode im Geltungsbereich.

Allgemeiner ausgedrückt:

Ich denke, es gibt ein grundlegendes Missverständnis darüber, wofür das new Schlüsselwort ist. Die Tatsache, dass Werttypen auf dem Stapel und "Referenz" Typen auf dem Heap allokiert werden, ist ein Implementierungsdetail. Das new Schlüsselwort ist Teil der Spezifikation. Als Programmierer interessiert es Sie nicht, ob es auf dem Heap oder auf dem Stapel allokiert wird (meistens), aber Sie müssen angeben, wie das Objekt initialisiert wird.

Es gibt auch andere gültige Arten von Initialisierern, wie zum Beispiel:

int[] values = { 1, 2, 3, 4 };

Voilà, eine Initialisierung ohne new. In diesem Fall war der Compiler intelligent genug, um es für Sie herauszufinden, weil Sie einen Literalausdruck bereitgestellt haben, der das gesamte Objekt definiert.

Also denke ich, meine "Antwort" ist, sich keine Sorgen darüber zu machen, wo sich das Objekt im Speicher befindet; verwenden Sie das new Schlüsselwort, wie es beabsichtigt ist, als Objektinitialisierer für Objekte, die Initialisierung erfordern.

5voto

tster Punkte 17284

Zum Anfang:

SomeClassType x;

wird nicht initialisiert, daher sollte kein Speicher allokiert werden.

Abgesehen davon, wie vermeiden Sie Probleme, wenn es eine Methode mit dem gleichen Namen wie die Klasse gibt.

Sagen wir, Sie schreiben etwas Code:

int World() { return 3; }

int hello = World();

und alles ist schön und fröhlich.

Jetzt schreiben Sie später eine neue Klasse:

class World 
{
    ...
}

Plötzlich ist Ihre int hello = World() Zeile mehrdeutig.

3voto

ristonj Punkte 1558

Aus Leistungsgründen ist dies möglicherweise keine gute Idee. Wenn Sie beispielsweise möchten, dass x ein Verweis auf ein bereits erstelltes Objekt ist, wäre es eine Verschwendung von Speicher und Prozessorzeit, ein neues Objekt zu erstellen und es sofort zu entsorgen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X