2011-06-29 15 views
7
public class A 
{ 
    private string _a_string; 
    public string AString 
    { 
     get { return _a_string; } 
     set { _a_string = value; } 
    } 
} 

public class B 
{ 
    private string _b_string; 
    private A _a; 

    public A A 
    { 
     get { return _a; } 
     set { _a = value; } 
    } 

    public string BString 
    { 
     get { return _b_string; } 
     set { _b_string = value; } 
    } 
} 

nie działa:Dlaczego to przypisanie C# rzuca wyjątek?

B _b = new B { A = { AString = "aString" }, BString = "bString" }; 

System.NullReferenceException: obiekt odniesienia nie jest ustawiony na przykład obiektu.

to działa:

B _b = new B { A = new A { AString = "aString" }, BString = "bString" }; 

Zarówno skompilować grzywny w VS2010.

+0

Dzięki za edycji, @ryeguy –

Odpowiedz

4

Nie ma instancji A w obrębie B, chyba że wyraźnie ją utworzysz, tak jak w drugim przykładzie.

Zmień na;

public class B 
{ 
    private string _b_string; 
    private A _a = new A(); 

    public A A 
    { 
     get { return _a; } 
     set { _a = value; } 
    } 

    public string BString 
    { 
     get { return _b_string; } 
     set { _b_string = value; } 
    } 
} 

Aby użyć pierwszego przykładu.

W skrócie, bez nowej A() nie ma który jest przyczyną NullReferenceException

+0

Dzięki - Wiem, jak zmusić go do pracy teraz, ale ja naprawdę myślał = {AString = "aString"} było wystarczającym przydziałem. –

5

Linia

B _b = new B { A = { AString = "aString" }, BString = "bString" }; 

odpowiada

B _b = new B(); 
_b.A.AString = "aString"; // null reference here: _b.A == null 
_b.BString = "bString"; 

Myślę, że w tej formie jest jasne, co się dzieje.

Porównaj to z równoważnej formie ekspresji, który działa:

B _b = new B(); 
_b.A = new A(); 
_b.A.AString = "aString"; // just fine now 
_b.BString = "bString"; 
+0

Prawdopodobnie masz rację, ale pomyślałem, że A = {AString = "aString"} zajmie się tworzeniem instancji A na własną rękę. Myślę, że będę musiał spojrzeć na IL, aby naprawdę dowiedzieć się ... –

+0

@ OtávioDécio: Nie, ponieważ kompilator po prostu przekształca składnię "skróconą" w długą. Ale prawdę mówiąc, gdybyś spytał mnie godzinę temu, nie uznałbym problemu za wyrażenie prawne jako C#. – Jon

+0

Chociaż poprawiłem swój kod, uważam, że to zachowanie jest na tyle niebezpieczne, że powoduje pewne zamieszanie. Domyślam się, że będę musiał być bardziej ortodoksyjny przy inicjowaniu obiektów od teraz. –

1

w pierwszym przypadku, kod jest skutecznie przekształcone przez kompilator do

B b = new B(); 
A a = b.A; 
a.AString = "aString"; 
b.BString = "bString"; 

Ponieważ nigdy nie przypisano b.A do instancja, dostajesz wyjątek (konkretnie, ponieważ nigdy nie przypisałeś b.A, a jest pusty i dlatego a.AString zamierza rzucić NullReferenceException). Fakt, że nigdzie nie ma kodu postaci new A... jest ogromną wskazówką, że instancja A nigdy nie została utworzona.

Można rozwiązać ten problem, dodając A = new A() do konstruktora B lub dodając inicjator pola do B._a.

W drugim przypadku kod jest przekształcany przez kompilator do

B b = new B(); 
A a = new A(); 
a.AString = "aString";  
b.A = a; 
b.BString = "bString"; 

To jest w porządku, bo teraz mamy instancję A.

+0

Dziękuję - ale dlaczego kompilator nie tworzy nowej instancji klasy A podczas pisania A = {AString = "aString"}? –

+1

Ponieważ nie używałeś 'nowego A' w dowolnym miejscu. Nie stworzy instancji, chyba że jej to powiesz. Mówisz to za pomocą słowa kluczowego 'new'. – jason

+0

Ponieważ nie ma jawnej instancji klasy A w klasie lub kodzie. W miejscu, w którym piszesz A = {AString = "aString"}, nie istnieje. – ChrisBint

0

Nie można używać

A = { AString = "aString" } 

z powodu tego samego powodu zrobił

B _b = new B { 

należy zadeklarować instancję B (i) w celu wykorzystania go.

Jeżeli masz napisane

B = B{... 

chcesz uzyskać podobny błąd

+0

@Reed - Jeśli nie mogę, to jest w porządku, ale jeśli tak - dlaczego kompilator go bierze? –

+0

Ponieważ w czasie kompilacji nie próbujesz uzyskać dostępu do A, więc zostanie skompilowany. Kompilator wie, że A jest prawidłową klasą, ale nie jest w stanie określić w tym momencie, czy została ona utworzona, czy nie, ponieważ może się to zdarzyć w innych miejscach. – ChrisBint

+0

@Chris - Dokładnie. – Reed

Powiązane problemy