14 votes

Bug d'initialisation d'objet en C# ?

using System;
using System.Collections.Generic;

class Parent
{
   public Child Child { get; set; }
}

class Child
{
   public List<string> Strings { get; set; }
}

static class Program
{
   static void Main() {
      // bad object initialization
      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };
   }
}

Le programme ci-dessus se compile correctement, mais se bloque au moment de l'exécution avec La référence d'objet ne correspond pas à une instance de l'objet .

Si vous remarquez dans l'extrait ci-dessus, j'ai omis nouveau lors de l'initialisation des propriétés de l'enfant.

Il est évident que la manière correcte de procéder à l'initialisation est la suivante :

      var parent = new Parent() {
         Child = new Child() {
            Strings = new List<string> { "hello", "world" }
         }
      };

Ma question est la suivante : pourquoi le compilateur C# ne se plaint-il pas lorsqu'il voit la première construction ?

Pourquoi la syntaxe de l'initialisation interrompue est-elle valide ?

      var parent = new Parent() {
         Child = {
            Strings = { "hello", "world" }
         }
      };

14voto

Jeroen Vannevel Points 18676

Ce n'est pas la syntaxe qui est cassée, c'est vous qui utilisez un initialisateur d'objet sur une propriété qui n'est tout simplement pas instanciée. Ce que vous avez écrit peut être développé comme suit

var parent = new Parent();
parent.Child.Strings = new List<string> { "hello", "world" };

Ce qui jette le NullReferenceException : vous essayez d'assigner la propriété Strings contenu dans le bien Child alors que Child est toujours null . Utiliser un constructeur pour instancier Child s'occupe de cela.

9voto

Guffa Points 308133

Il n'y a pas de problème avec l'initialisation, mais il essaie d'initialiser des objets qui n'existent pas.

Si les classes ont des constructeurs qui créent les objets, l'initialisation fonctionne :

class Parent {
  public Child Child { get; set; }
  public Parent() {
    Child = new Child();
  }
}

class Child {
  public List<string> Strings { get; set; }
  public Child() {
    Strings = new List<string>();
  }
}

3voto

Colin Grealy Points 161

La seconde syntaxe est valable pour les propriétés en lecture seule. Si vous modifiez le code pour initialiser les propriétés Child et Strings dans les constructeurs respectifs, la syntaxe fonctionne.

class Parent
{
    public Parent()
    {
        Child = new Child();
    }

    public Child Child { get; private set; }
}

class Child
{
    public Child()
    {
        Strings = new List<string>();
    }
    public List<string> Strings { get; private set; }
}

static class Program
{
    static void Main()
    {
        // works fine now
        var parent = new Parent
        {
            Child =
            {
                Strings = { "hello", "world" }
            }
        };

    }
}

2voto

GSerg Points 33571

Vous semblez ne pas comprendre ce que fait l'initialisateur de collection.

Il s'agit d'un simple sucre syntaxique qui convertit la liste entre accolades en un série d'appels à Add() méthode qui doit être définie sur l'objet de collection initialisé.
Votre = { "hello", "world" } a donc le même effet que

.Add("hello");
.Add("world");

Il est évident que cette opération se soldera par une exception de type NullReferenceException si la collection n'est pas créée.

1voto

Russell Harkins Points 333

La référence à une valeur nulle ne peut pas toujours être vérifiée au moment de la compilation. Bien que le compilateur prévienne parfois de l'utilisation d'une variable avant qu'elle n'ait été assignée. Le compilateur fonctionne correctement. Il s'agit d'une erreur d'exécution.

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