In this chapter, you learned about object creation and, in particular, about constructors and their ability to perform useful actions when a new object is created. The chapter also looked at how memory, otherwise occupied by an object that no longer can be reached, is released with garbage collection, and how other scarce resources can be released with the Dispose design pattern.
The following paragraphs review the important points covered in this chapter.
An instance variable can be initialized in three different ways:
Automatically by the runtime. In which case, the instance variable is assigned a default value. The default value depends on the type of the instance variable.
Using a declaration initialization, which allows the programmer to specify the initialization value.
Using a constructor, which is a function member that allows the programmer to include any number of statements that are to be executed when the object is created.
Constructors are often needed to perform initializations that involve the execution of several statements. They are also suited to perform other actions than initializations that are required when the object is created.
An instance constructor is called when the keyword new is used to create a new object.
If you don't specify any constructors for a class, a default constructor will automatically be included by the compiler. A default constructor takes no arguments.
Several constructors can be included in the same class, in which case, they become overloaded in a similar fashion to that of overloaded methods. The formal parameters of overloaded constructors must, like their overloaded method cousins, differ in terms of their types or their amount, or both.
The constructor initializer allows you to specify that a constructor, on its initiation, calls another constructor prior to the execution of its own method body. This can save you from including the same set of statements in several overloaded instance constructors.
You can prevent any objects to be instantiated from a class by declaring all its instance constructors (usually just one) to be private. This can be useful with classes that only contain static members.
A static constructor is not called directly from the source code, but is called automatically by the runtime sometime between the start of the program and the instantiation of the first object of the class. The static constructor is most commonly used to initialize static variables.
The value of a constant variable must be written in the source code, so it remains unchangeable from the time a program is compiled. In contrast, a readonly variable is initialized during runtime when its object is created and remains unchangeable during the lifetime of the object.
When no references exist to an object, it is out of reach and becomes eligible for garbage collection. Four examples of objects becoming unreachable were discussed:
When all references to an object are assigned the null reference, this object goes out of reach.
When a reference variable (holding the only reference to an object A) is assigned a different reference, object A goes out of reach.
When an object A contains the only reference to an object B, both object A and B go out of reach when object A goes out of reach.
When a local variable, which contains the only reference to an object, goes out of scope the object becomes unreachable.
The garbage collector works by default behind the scenes on every C# program; it is managed automatically by the runtime. It detects unreachable objects and reclaims their memory. The garbage collector is finely tuned to work in the background, and should only be interfered with in rare cases.
The garbage collector does not promise when it collects an unreachable object. It might not occur until after the program has finished interacting with the user.
A destructor is a class member containing executable statements that are executed as part of the garbage collector's memory reclamation.
Objects can occupy other scarce resources than memory, such as files and network connections. The garbage collector does not free these types of resources, and the destructor is not suited to carry out this task because of the garbage collector's timing uncertainties.
The programmer should implement his or her own system to detect when scarce non-memory resources must be freed and write the actual code that frees those resources. Microsoft recommends programmers to use the "Dispose design pattern" for this purpose.