36 votes

Je ne comprends pas pourquoi nous avons besoin du mot clé "nouveau"

Je suis nouveau en C #, à partir d'un arrière-plan C ++. En C ++, vous pouvez faire ceci:

 class MyClass{
....
};
int main()
{
   MyClass object; // this will create object in memory
   MyClass* object = new MyClass(); // this does same thing
}
 

Considérant que, en C #:

 class Program
{
    static void Main(string[] args)
    {
        Car x;
        x.i = 2;
        x.j = 3;
        Console.WriteLine(x.i);
        Console.ReadLine();

    }
}
class Car
{
    public int i;
    public int j;


}
 

tu ne peux pas faire ça. Je me demande pourquoi Car x ne fera pas son travail.

48voto

Eric Lippert Points 300275

Il y a beaucoup d'idées fausses ici, à la fois dans la question elle-même et de plusieurs réponses.

Permettez-moi de commencer par l'examen de la prémisse de la question. La question est "pourquoi avons-nous besoin de l' new mot-clé en C#?" La motivation pour la question est ce fragment de C++:

 MyClass object; // this will create object in memory
 MyClass* object = new MyClass(); // this does same thing

Je reproche à cette question pour deux raisons.

Tout d'abord, ne pas faire la même chose en C++, donc la question est basée sur une mauvaise compréhension du langage C++. Il est très important de comprendre la différence entre ces deux choses en C++, donc si vous ne comprenez pas très clairement ce qu'est la différence, trouver un mentor qui peut vous enseigner comment savoir quelle est la différence, et lors de l'utilisation de chacun.

Deuxièmement, la question suppose -- erroné et que ces deux syntaxes de faire la même chose en C++, et puis, bizarrement, s'interroge: "pourquoi avons-nous besoin d' new en C#?" Sûrement la bonne question à se poser compte tenu de cela, encore une fois, faux-présupposition est "pourquoi avons-nous besoin d' new en C++?" Si ces deux syntaxes de faire la même chose, qu'ils ne sont pas, alors pourquoi deux syntaxes en premier lieu?

Donc, la question est à la fois basée sur une fausse prémisse, et la question sur le C# n'a pas fait suivre à partir de la -- incomprise-conception de C++.

C'est un gâchis. Nous allons jeter cette question et de poser quelques bonnes questions. Et posons-nous la question sur le C# qua C#, et non dans le contexte de la conception des décisions de C++.

Ce qui ne l' new X opérateur de le faire en C#, où X est une classe ou d'un type struct? (Nous allons ignorer les délégués et les tableaux pour les fins de cette discussion.)

L'opérateur new:

  • Les Causes d'une nouvelle instance d'un type donné d'être allouées; de nouvelles instances ont tous leurs champs initialisés aux valeurs par défaut.
  • Les Causes d'un constructeur de ce type à être exécuté.
  • Produit une référence à l'allocation d'un objet, si l'objet est un type de référence, ou de la valeur elle-même si l'objet est un type valeur.

Tout droit, j'entends déjà les objections de la part de C#, programmeurs, afin de laisser de la rejeter.

Objection: pas de nouvelle de stockage est alloué si le type est un type valeur, je vous entends dire. Ainsi, la spécification C# n'est pas d'accord avec vous. Quand vous dites

S s = new S(123);

pour certains type struct S, la spec dit que temporaire de stockage est alloué sur le court-terme de la piscine, initialisé à ses valeurs par défaut, de l'exécution du constructeur avec this ensemble pour se référer à la température de stockage, puis l'objet est copié à l' s. Cependant, le compilateur est autorisé à utiliser une copie-élision de l'optimisation à condition qu'il puisse prouver qu'il est impossible pour l'optimisation de devenir observée dans un programme de sécurité. (Exercice: travailler dans quelles circonstances une copie élision ne peut pas être effectuée; donner un exemple d'un programme qui aurait un comportement différent si élision a été ou n'a pas été utilisé.)

Objection: une instance valide de type valeur peut être produit en utilisant default(S); aucun constructeur est appelé, me direz-vous. C'est correct. Je n'ai pas dit qu' new est le seul moyen de créer une instance d'un type valeur.

En effet, pour une valeur type new S() et default(S) sont la même chose.

Objection: Est un constructeur réellement exécutées pour des situations comme new S(), si non présent dans le code source en C# 6, je vous entends dire. C'est un "si un arbre tombe dans la forêt et personne ne l'entend, est-il un son?" question. Est-il une différence entre un appel à un constructeur qui ne fait rien, et aucun appel à tous? Ce n'est pas une question intéressante. Le compilateur est libre d'éluder les appels qu'il sait ne rien faire.

Supposons que nous avons une variable de type valeur. Doit-on initialiser la variable avec une instance produite par new?

Pas de. Les Variables qui sont automatiquement initialisés, tels que les champs et les éléments du tableau, sera initialisé à la valeur par défaut-qui est, la valeur de la structure où tous les champs sont eux-mêmes à leurs valeurs par défaut.

Les paramètres formels sera initialisé avec l'argument, évidemment.

Les variables locales de type de valeur sont nécessaires pour être définitivement attribuées à quelque chose avant de les champs sont en lecture, mais il n'a pas besoin d'être un new expression.

Donc, effectivement, les variables de type valeur sont automatiquement initialisés avec l'équivalent d' default(S), à moins qu'ils sont les habitants?

Oui.

Pourquoi ne pas faire la même chose pour les habitants?

L'utilisation d'un non initialisée local est fortement associée avec le code bogué. Le langage C# n'autorise pas cela parce que faire trouve des bugs.

Supposons que nous avons une variable de type référence. Doit-on initialiser S avec une instance produite par new?

Pas de. Automatique-initialisation des variables sera initialisé avec la valeur null. Les habitants peuvent être initialisés avec toute référence, y compris null, et doit être définitivement attribuées avant de le lire.

Donc, effectivement, les variables de type référence sont automatiquement initialisés avec null, à moins qu'ils sont les habitants?

Oui.

Pourquoi ne pas faire la même chose pour les habitants?

Même raison. Un probable bug.

Pourquoi ne pas initialiser automatiquement les variables de type référence, en appelant le constructeur par défaut automatiquement? C'est, pourquoi ne pas faire R r; le même que R r = new R();?

Eh bien, tout d'abord, de nombreux types n'ont pas de constructeur par défaut, ou d'ailleurs, tout accessible constructeur à tous. Deuxièmement, il semble bizarre d'avoir une règle pour un non initialisée local ou de terrain, une autre règle officielle, et encore une autre règle pour un élément de tableau. Troisièmement, la règle est très simple: une variable doit être initialisée à une valeur, cette valeur peut être tout ce que vous voulez; pourquoi l'hypothèse qu'une nouvelle instance est souhaitée justifiée? Il serait bizarre si ce

R r;
if (x) r = M(); else r = N();

causé un constructeur à exécuter pour initialiser r.

En laissant de côté la sémantique de l' new opérateur, pourquoi est-il nécessaire du point de vue syntaxique d'avoir un opérateur?

Il n'est pas. Il ya un certain nombre de syntaxes alternatives qui pourraient être grammatical. Le plus évident serait de simplement éliminer l' new entièrement. Si nous avons une classe C avec un constructeur C(int) alors nous pourrions simplement dire C(123) au lieu de new C(123). Ou nous pourrions utiliser une syntaxe comme celle - C.construct(123) ou quelque chose de ce genre. Il y a un certain nombre de façons de le faire sans l' new de l'opérateur.

Alors pourquoi l'avoir?

Tout d'abord, C# a été conçu pour être immédiatement familier pour les utilisateurs de C++, Java, JavaScript et d'autres langages utilisent new nouvelle de stockage est en cours d'initialisation d'un objet.

Deuxièmement, le niveau de redondance syntaxique est hautement souhaitable. La création d'objet est particulière, nous souhaitons faire appel quand il arrive avec son propre opérateur.

28voto

Dmitry Bychenko Points 17719

En C#, vous pouvez faire le semblable chose:

  // please notice "struct"
  struct MyStruct {
    ....
  }

  MyStruct sample1; // this will create object on stack
  MyStruct sample2 = new MyStruct(); // this does the same thing

Rappelons que les primitives comme int, double, et bool sont également de type struct, donc même si c'est classique à écrire

  int i;

on peut aussi écrire

  int i = new int(); 

contrairement au C++, C# ne pas utiliser des pointeurs (en mode de sécurité) pour les instances, cependant, C# a class et struct déclarations:

  • class: vous avez de référence à l'instance, la mémoire est allouée sur le tas, new est obligatoire; semblable à l' MyClass* en C++

  • struct: vous avez de la valeur, la mémoire est (généralement) alloué sur la pile, new est facultatif; semblable à l' MyClass en C++

Dans votre cas particulier, vous pouvez simplement tourner Car en struct

struct Car
{
    public int i;
    public int j;
}

et si le fragment

Car x; // since Car is struct, new is optional now 
x.i = 2;
x.j = 3;

sera correct

15voto

Matti Virkkunen Points 31633

En C#, class type les objets sont toujours alloués sur le tas, c'est à dire des variables de ce type sont toujours des références (pointeurs). Juste de déclarer une variable de ce type n'a pas l'allocation d'un objet. L'allocation d'un class objet sur la pile comme il est commun de le faire en C++ n'est pas (en général) une option en C#.

Les variables locales de toute nature, qui n'ont pas été assigné sont considérés comme non initialisée, et ils ne peuvent pas être lus jusqu'à ce qu'ils ont été affectés. C'est un choix de conception (d'une autre façon, aurait été d'attribuer default(T) pour chaque variable au moment de la déclaration) qui semble être une bonne idée, parce que cela devrait vous protéger de certaines erreurs de programmation.

Il est similaire à la façon dont en C++ ça ne ferait pas de sens de dire SomeClass *object; et de ne jamais céder quoi que ce soit.

Parce qu'en C# tous class variables de type sont des pointeurs, l'allocation d'un objet vide lorsque la variable est déclarée conduirait à l'inefficacité de code lorsque vous avez réellement ne voulez affecter une valeur à la variable, plus tard, par exemple dans des situations de ce genre:

// Needs to be declared here to be available outside of `try`
Foo f;

try { f = GetFoo(); }
catch (SomeException) { return null; }

f.Bar();

Ou

Foo f;

if (bar)
    f = GetFoo();
else
    f = GetDifferentFoo();

12voto

zacaj Points 530

ignorer le côté pile / tas des choses:

parce que C # a pris la mauvaise décision de copier C ++ alors qu’il aurait juste dû faire la syntaxe

 Car car = Car()
 

(ou quelque chose de similaire). Avoir 'nouveau' est superflu.

7voto

Vlad from Moscow Points 36219

Lorsque vous utilisez référencé types puis dans la présente déclaration

Car c = new Car();

il y a créé deux entités: une référence nommée c pour un objet de type Voiture dans la pile, et l'objet de type Voiture elle-même dans le tas.

Si vous il suffit d'écrire

Car c;

ensuite, vous créez une non initialisé de référence (à condition qu' c est une variable locale) qui pointe vers nulle part.

En fait, c'est équivalent à du code C++ où, au lieu de références, on utilise des pointeurs.

Par exemple

Car *c = new Car();

ou tout simplement

Car *c;

La différence entre C++ et C# est que le C++ peut créer des instances de classes dans la pile comme

Car c;

En C#, cela signifie la création d'une référence de type de Voiture que comme je l'ai dit les points de nulle part.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X