Initialization синтаксис может быть сложнее. В вашем коде вы пытаетесь установить значение a.B.X
, не устанавливая сначала значение B
. Ваш код переводит на:
var a = new A();
a.B.X = 1;
... который будет производить то же исключение, которое вы получаете сейчас. Это потому, что a.B
инициализирован до null
, если вы явно не создали для него экземпляр.
Как вы отметили, что это будет работать:
var a=new A{
B= new _B {
X=1
}
};
Вы также можете убедиться, что конструктор A
«s инициализирует B
.
public class A
{
public _B B = new A._B();
public class _B
{
public int X;
}
}
why it compiles fine without new and then fails during runtime?
Это потребовало бы слишком много работы для компилятора, чтобы копаться в коде для A
класса и понимают, что B
, безусловно, будет нулевой в данный момент: как я указал, вы можете изменить реализация конструктора A
, чтобы убедиться, что это не так. Это одна из причин, по которой исключения с нулевой ссылкой являются наиболее распространенным типом исключения.
Лучшей стратегией, чтобы избежать этого, является инициализация всех ваших полей ненулевыми значениями в конструкторе. Если вы не знаете, какое значение им нужно дать, пока ваш конструктор не будет вызван, тогда сделайте свой конструктор такими значениями в качестве параметров. Если вы ожидаете, что одно из ваших полей может не всегда иметь значение, вы можете использовать необязательный тип like my Maybe<>
struct, чтобы заставить программистов справиться с этим фактом во время компиляции.
В частности, см. Раздел ** Косвенный ** в принятом ответе. –
Потому что в вашем примере вы не инициализируете B. Вы в основном делаете a.B.X = 1, где B все еще null. –
Вы спрашиваете, почему вы получили NRE или почему компилятор не предупреждает вас об использовании переменной B, не создавая ее раньше? – Steve