Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why throwing exception in constructor results in a null reference?

Why throwing exception in constructor results in a null reference? For example, if we run the codes below the value of teacher is null, while st.teacher is not (a Teacher object is created). Why?

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;
  }

}
like image 820
Setyo N Avatar asked Apr 12 '12 08:04

Setyo N


3 Answers

The constructor never completes, therefore the assignment never occurs. It's not that null is returned from the constructor (or that there's a "null object" - there's no such concept). It's just that you never assign a new value to teacher, so it retains its previous value.

For example, if you use:

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

... then you'll still have the "This is valid" teacher. The name variable still won't be assigned a value in that Teacher object though, as your Teacher constructor is missing a line such as:

this.name = name;
like image 67
Jon Skeet Avatar answered Nov 07 '22 06:11

Jon Skeet


Cause you're checking the 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 );
  }

but

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." );
}
like image 13
Tigran Avatar answered Nov 07 '22 07:11

Tigran


When you throw an exception in a constructor, you break object's construction. So it's never finished and hence, there's no object to return. In fact, that assignment operator (teacher = new Teacher( "", st );) is never executed since exception breaks the calling stack.

And the Teacher constructor still writes a reference to itself (the object being constructed) into the Student object's property. But you should never try using this Teacher object afterwards, since it has not been constructed. It may result in undefined behavior.

like image 3
Dmytro Shevchenko Avatar answered Nov 07 '22 06:11

Dmytro Shevchenko