Затем я создаю два экземпляра класса:
Вы не создавая каких-либо экземпляров. Вы создаете два места для размещения экземпляров, если они когда-либо создаются.Первое, что вы явно сказали, не имеет экземпляра, у второго нет его.
Есть ли разница между Instance1
и Instance2
?
Это зависит от того, где вы это сделали.
Если код находится в пределах class
или struct
то вы создали два поля, оба из которых будут установлены в null
первоначально, если конструктор не делает что-то другое.
Если у вас есть этот код внутри метода (включая конструктор или свойство accessor), то у вас есть две локальные переменные (хотя соглашение будет заключаться здесь в нижнем регистре).
Первый был установлен в null, и вы можете делать с ним что-то, что можно сделать с нулевым (передать его методу [хотя это может выдать исключение, если оно отказывается принять null) сравнить его с что-то, чтобы подтвердить, что оно действительно является нулевым или не является тем же самым, что и то, что действительно имеет экземпляр.
Вторая не была назначена, и поэтому незаконно делать что-либо другое, кроме как назначить ей что-нибудь (нуль или экземпляр). Любая попытка сделать что-либо, прежде чем он определенно будет установлен, будет ошибкой компилятора. Например .:
MyClass Instance2;
if (valueThatJustHappensToAlwaysBeTrue)
{
Instance2 = new MyClass();
}
bool isNull = Instance2 == null; // Error! Not guaranteed to be assigned strongly enough for the compiler to know.
Это да, это безопасно, и это хорошая привычка иметь Instance2
только с декларацией?
Когда это возможно, это хорошая привычка быть объявляя как можно ближе к первому заданию (инициализации), как это возможно, в идеале, в то же время:
MyClass instance = new MyClass();
Однако, если у Вас есть несколько различные возможные пути, такие как:
MyClass instance;
if (boolValue)
{
instance = new MyClass(1); // Yes, I know there's no int-taking ctor on your class, but it defeats the argument when the bare constructor is the only one available, so let's say there is.
}
else if (otherBoolValue)
{
throw new SomeException();
}
else if (someIntValue > 42)
{
instance = new MyClass(3);
}
else
{
instance = new MyClass(9);
}
Теперь это невозможно, чтобы добраться до конца этой цепи с неинициализированной instance
. Либо он будет установлен, либо исключение будет выброшено. Если бы мы подумали, что это может быть «безопаснее» начинаться с MyClass instance = null
, мы могли бы скрыть ошибку. Вышеупомянутая логика предназначена для присвоения ей чего-то для каждого пути и из-за правила, что вы не можете использовать экземпляр, который не гарантированно назначается, ошибка в этом вызовет ошибку компилятора, и ошибка будет очевидна , Если он присваивается нулевому значению «заполнителя», чтобы начать с такой ошибки, это не будет столь очевидным, и может вызвать ошибку.
Так что в таких случаях, как голая декларация, лучше.
Но при этом сложная логика всегда лучше избегается, когда это возможно, поэтому такие свернутые цепи должны быть редкими. В других случаях стиль объявления и назначения в той же точке означает, что вы не имеете разрыв между ними, где ошибка может проскользнуть в.
Первый является переменной, которая была инициализирована с 'null', последний является varibale, не инициализирована явно, поэтому получает значение по умолчанию, которое тоже нуль. Разница заключается в следующем: читаемость, все знают, что нуль является желательным и ожидаемым. Если у вас есть 'out' paramater, компилятор заставляет вас что-то присваивать, даже если это« null ». –
Например, Resharper предложит удалить в этом случае назначение «null». – Fabio
Да, есть разница. Во втором случае, если значением является поле, ему автоматически присваивается значение по умолчанию, но если это локальная переменная, это не будет. Если он затем «считывается» кодом, это приводит к ошибке компилятора «использование неназначенной локальной переменной». – stuartd