2015-06-03 13 views
17

Poniższa procedura testowa zgłasza wyjątek o wartości null, próbując przydzielić identyfikator obiektowi, który ma wartość null, ponieważ kodowi brakuje "nowego R" przed inicjalizatorem obiektu.Dlaczego ten zagnieżdżony inicjalizator obiektów generuje wyjątek odwołania o wartości zerowej?

Dlaczego to nie jest przechwycone przez kompilator? Dlaczego jest dozwolone, w którym przypadki użycia byłyby znaczącą konstrukcją?

[TestClass] 
public class ThrowAway 
{ 
    public class H 
    { 
     public int Id { get; set; } 
    } 

    public class R 
    { 
     public H Header { get; set; } 
    } 

    [TestMethod] 
    public void ThrowsException() 
    { 
     var request = new R 
         { 
          Header = 
          { 
           Id = 1 
          }, 
         }; 
    } 
} 
+0

Musisz zainicjować właściwość Header swojego obiektu R. 'var request = new R {Header = new H {ID = 1}};' – Styxxy

+3

Bardzo interesujące pytanie ... nie jest nawet jasne, czy kompilator wykonuje obsadę, czy co ... – xanatos

+3

Bardzo interesujące pytanie, ale bardzo słaby tytuł w mojej opinii. Czy rozważasz zmianę go na pytanie, które zadajesz? – julealgon

Odpowiedz

18

Kompilator nie dać ostrzeżenie, ponieważ można mieć:

public class R 
{ 
    public H Header { get; set; } 

    public R() 
    { 
     Header = new H(); 
    } 
} 

tak Header można zainicjować przez kogoś/czegoś. Rozwiązywanie jeśli ktoś/coś zainicjuje Header jest złożonym problemem (prawdopodobnie podobna do powstrzymania problemu) ... Nie coś, że chce rozwiązać kompilator dla Ciebie :-)

od C# specyfikacji:

Inicjator członka, który określa inicjator obiektu po znaku równości, jest inicjatorem zagnieżdżonego obiektu, tj. Inicjalizacją osadzonego obiektu. Zamiast przypisywania nowej wartości do pola lub właściwości, przypisania w inicjatorze zagnieżdżonego obiektu są traktowane jako przypisania do elementów pola lub właściwości. Zagnieżdżone inicjalizatory obiektów nie mogą być stosowane do właściwości z typem wartości lub do pól tylko do odczytu z typem wartości.

Jesteśmy w przypadku inicjatora zagnieżdżonego i zobacz pogrubioną część. Nie wiedziałem tego.

Teraz należy pamiętać, że new R { } jest przez C# specyfikacji, 7.6.10.1 Object creation expressions następnie przez object-initializer, natomiast Header = { } jest "czysta" 7.6.10.2 Object initializers.

+1

To samo pytanie co do innego postu tutaj - dlaczego zezwolono na 'Header = {Id = 1}'? I tak wygląda to nie tak, prawda? – Andrei

+0

@Andrei Przynajmniej wyjaśniłem * Dlaczego nie jest to przechwycone przez kompilator? * :-) – xanatos

+0

Niestety, nadal nie rozumiem. Nie próbuję się kłócić, tylko bardzo ciekawi siebie. Kompilator powinien mieć nie powiodła się na takiej składni, bez względu na to, czy jest inicjalizacja w ctor, prawda? – Andrei