Вопрос по exception, constructor, c#, object, null – Почему исключение в конструкторе приводит к пустой ссылке?

20

Почему исключение в конструкторе приводит к пустой ссылке? Например, если мы запускаем коды ниже, значение учителя равно нулю, а st.teacher - нет (создается объект учителя). Зачем?

<code>using System;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main( string[] args )
    {
      Test();
    }

    private static void Test()
    {
      Teacher teacher = null;
      Student st = new Student();
      try
      {
        teacher = new Teacher( "", st );
      }
      catch ( Exception e )
      {
        Console.WriteLine( e.Message );
      }
      Console.WriteLine( ( teacher == null ) );  // output True
      Console.WriteLine( ( st.teacher == null ) );  // output False
    }
  }

  class Teacher
  {
    public string name;
    public Teacher( string name, Student student )
    {
      student.teacher = this;
      if ( name.Length < 5 )
        throw new ArgumentException( "Name must be at least 5 characters long." );
    }
  }

  class Student
  {
    public Teacher teacher;
  }

}
</code>

Ваш Ответ

6   ответов
1

Foo это ссылочный тип, операторFoo = new FooType(); построит объект, а затем,after the constructor has completedсохранить ссылку вFoo, конструктор выдает исключение, код, который будет хранить ссылку вFoo будут пропущены безFoo будучи написанным.

В случаях, когда:

A statement like the above occurs within a try/catch block The statement can be reached without Foo having been written beforehand. Foo a local variable defined in a context surrounding the catch block. It is possible for execution starting at the catch to reach a statement which reads Foo without its having written in after the catch.

Компилятор предположит, что последняя попытка чтенияFoo может быть выполнен безFoo будучи написанным, и в этом случае откажется от компиляции. Компилятор позволитFoo тем не менее, если он не был написан, если:

Foo is a class field, or a field of a struct stored in a class field, a field of a struct stored in a field of a struct stored in a class field, etc. Foo is passed as an out parameter to a method (written in a language other than C#) that doesn't store anything to it, and the statement which reads foo would only be reachable if the method had returned normally rather than via exception.

В первом случае,Foo будет иметь определенное значениеnull, В последнем случае значениеFoo скорее всего, будет нулевым при первом создании во время выполнения метода; если воссоздан в цикле, он может содержатьnull или последнее значение, записанное в него после последнего создания; Стандарт не конкретен в отношении того, что произойдет в этой ситуации.

Обратите внимание, что еслиFooType имеет что-то похожее на нормальный конструктор,Foo = new FooType(); никогдаcause Foo становиться нулевым, если это не было раньше. утверждение завершается нормально,Foo будет содержать ссылку на экземпляр точного типаFooType на что ранее нигде во вселенной не существовало никаких ссылок; если он выдает исключение, это не повлияетFoo в любом случае.

-1

ации есть исключение, само по себе нет смысла иметь объект, который не был должным образом инициализирован. Следовательно, исключение из конструктора приводит к нулевому объекту.

Это не правильно; это не приводит ни к чему, как указано в других ответах.
37

поэтому назначение никогда не происходит. Это не означает, что нуль возвращается из конструктора (или что отсутствует «нулевой объект» - такого понятия нет). Просто вы никогда не назначаете новое значениеteacher, поэтому он сохраняет свое предыдущее значение.

Например, если вы используете:

Teacher teacher = new Teacher("This is valid", new Student());
Student st = new Student();
try
{
    teacher = new Teacher("", st);
}
catch (... etc ...)

... тогда у вас все равно будет "Это действительно" учитель.name переменной по-прежнему не будет присвоено значение в этомTeacher возражать, хотя, как вашTeacher В конструкторе отсутствует строка, такая как:

this.name = name;
@ Привет-Ангел: Нет, это не ошибка. Это разница междуfield и локальная переменная. Поле имеет значение по умолчанию и может использоваться, даже не будучи установленным - локальная переменнаяcannot читать до тех пор, пока он не будет определенно назначен.
спасибо за отличное объяснение, я отредактировал "нулевой объект" в вопросе "нулевая ссылка". Setyo N
Отличное объяснение, также вы только что доказали, что неинициализированный объект в C # всегда содержит & # xAB; null & # xBB ;. Я начал сомневаться в этом, потому что, когда я пытался использовать в Visual Studio объект, который мог быть неинициализирован в определенных условиях, но в любом случае он был проверен на наличие & # xAB; null & # xBB; и затем использован, компилятор показал ошибку о неинициализированной переменной. После того как я явно инициализировал объект с помощью & # xAB; null & # xBB ;, ошибка исчезла. Благодаря вам, теперь я знаю, что это просто ошибка Visual Studio.
13

referencies.

  try
  {
    teacher = new Teacher( "", st ); //this line raises an exception 
                                     // so teacher REMAINS NULL. 
                                     // it's NOT ASSIGNED to NULL, 
                                     // but just NOT initialized. That is.
  }
  catch ( Exception e )
  {
    Console.WriteLine( e.Message );
  }

но

public Teacher( string name, Student student )
{
  student.teacher = this;  //st.Teacher is assigned BEFORE exception raised.
  if ( name.Length < 5 )
    throw new ArgumentException( "Name must be at least 5 characters long." );
}
3

вы нарушаете конструкцию объекта. Таким образом, он никогда не завершается и, следовательно, нет объекта для возврата. На самом деле, этот оператор присваивания (teacher = new Teacher( "", st );) никогда не выполняется, так как исключение нарушает стек вызовов.

И конструктор Учителя все еще записывает ссылку на себя (конструируемый объект) в свойство объекта Student. Но вы никогда не должны пытаться использовать этот объект Учителя впоследствии, так как он не был создан. Это может привести к неопределенному поведению.

0

& gt; ученик.учитель = это; // Эта строка выполнена       if (name.Length & lt; 5) // Это проверено и верно в указанном случае         throw new ArgumentException (& quot; имя должно быть длиной не менее 5 символов. & quot;); // BAM: здесь выдается исключение. & apos;

Таким образом, значение учителя равно нулю (как исключение, выбрасываемое до завершения конструктора), а st.teacher - нет!

Похожие вопросы