Friday, January 15, 2016

Lesson 2

Outline


Chapter 10
  • Constructors
    • Default/Parameterless
    • Overloaded Constructors
  • Destructors
  • Static Class Members
  • Read Only Instance Field
Constructors

We introduced the concept of a class constructor last week. We will expand on it this week using overloaded constructors. A class can support one to many constructors in a class. It must follow these rules:

All constructors must have the same name as the class.
All constructors must have a different combination of parameter types.


namespace Chapter10_HousePlans_Sample
{
    /// <summary>
    /// Simple house plans class
    /// </summary>
    class HousePlans
    {
        /// <summary>
        /// Private (not visible outside of class) variable to keep track of door status (defaults to false:closed)
        /// </summary>
        private bool doorOpened;
        private int bedrooms;
        private int bathrooms;
 
        /// <summary>
        /// Public (visible outside the class and even the project) method to change to the door open status to true:opened
        /// </summary>
        public void OpenDoor()
        {
            doorOpened = true;
        }
 
        public HousePlans()
        { 
        }
 
        public HousePlans(int bedrooms)
        {
            this.bedrooms = bedrooms;
        }
 
        public HousePlans(int bedrooms, int bathrooms)
        {
            this.bedrooms = bedrooms;
            this.bathrooms = bathrooms;
        }
 
        /// <summary>
        /// Public (visible outside the class and even the project) method to change to the door open status to false:closed
        /// </summary>
        public void CloseDoor()
        {
            doorOpened = false;
        }
 
        /// <summary>
        /// Overrides the standard tostring method (available in all object) to a specific string
        /// </summary>
        /// <returns>Status of the door(open or closed)</returns>
        public override string ToString()
        {
            return "The door is " + (doorOpened ? "Open" : "Closed");
        }
    }
}

In our sample class above we have three constructors, a parameterless constructor, a constructor that takes one integer, and a constructor that takes two integers. Note each constructor takes a different number of parameters. We could also differentiate constructors by the type of parameter as well.

public HousePlans(int bedrooms)
{
    this.bedrooms = bedrooms;
}
 
public HousePlans(string paintColor)
{
    this.paintColor = paintColor;
}

If we had two constructors in our class that each took a single parameter as in our example above, there would be no conflict. Even though the constructors are identical in the number of parameters they still differ by type. One constructor takes an integer parameter and the other takes a string. Also, once we add our own constructor the hidden default constructor is removed. If we still want a parameterless constructor in our class we will need to manually define it.

NOTE: THE PARAMETER NAMES NOT CONSIDERED WHEN OVERLOADING A CONSTRUCTOR. ONLY THE NUMBER OF PARAMETERS AND THIER TYPES.

Destructors

A constructor creates an instance of an object based on a class. A destructor destroys the created object allowing the system garbage collection to free up any resources used by the object. Without destructors the application could grow in memory taking up more and more resources. This is called a resource or memory leak.

To implement a destructor in our class we implement the IDisposable interface within our class. Implementing an interface in a class will cause the class to stub out code necessary to support the interface functionality.

Adding the IDisposable interface to our HousePlans class:
class HousePlansIDisposable

To add the interface to our class, we add a colon to the right of the class name. After the interface is added it must be implemented (supported) within the class. To implement the IDisposable interface click on the word "IDisposable" and a small underscore will appear.








After the underscore appears, hover the cursor over it to enable a small drop down.












When the menu appears, click the "Implement interface IDisposable". Viewing the code of the class you will notice a new method "Dispose"


public void Dispose()
{
    throw new NotImplementedException();
}


Remove the "throw new NotImplementedException():". Once implemented, you can "dispose" of your object like this:


//Creates an instance of the class
HousePlans myHouse = new HousePlans();
//Disposes or removes the instance of the class
myHouse.Dispose();


It is a good idea to implement the IDisposable interface even though we are not doing anything within the dispose method. It does provide a nice way to remove any unused objects as well as a place holder when we do need to perform some tasks when disposing of an object. We will discuss that in a later lesson.


Static Class Members


A static class is basically the same as a non-static class, but with one difference. A static class cannot be instantiated. That is, we cannot create an instance of a static class (i.e. use the new keyword). Static classes are generally used to hold to hold methods that do not rely on an instance value.


You may recall in the previous lesson creating the myHouse and yourHouse objects. While based on the same class they may still contain different attribute values. These differences are based on the instance of the object. A static class does not use any instance settings and therefore does not require the new keyword.


public static class TemperatureConverter
{
    public static double CelsiusToFahrenheit(string temperatureCelsius)
    {
        // Convert argument to double for calculations. 
        double celsius = Double.Parse(temperatureCelsius);
 
        // Convert Celsius to Fahrenheit. 
        double fahrenheit = (celsius * 9 / 5) + 32;
 
        return fahrenheit;
    }
 
    public static double FahrenheitToCelsius(string temperatureFahrenheit)
    {
        // Convert argument to double for calculations. 
        double fahrenheit = Double.Parse(temperatureFahrenheit);
 
        // Convert Fahrenheit to Celsius. 
        double celsius = (fahrenheit - 32) * 5 / 9;
 
        return celsius;
    }
}


This class has the same look and feel of the HousePlans class with one exception. Notice the keyword "static", this denotes that the class does require an instance to access the methods. To use the HousePlans methods we had to create an instance of the HousePlans class.


//Creates an instance of the class
HousePlans myHouse = new HousePlans();
//Access method within the new instance
myHouse.CloseDoor();
//Disposes or removes the instance of the class
myHouse.Dispose();


To access a method within a static class we only need to call the method directly.


//Static classes/methods do not require an instance to be accessed
TemperatureConverter.CelsiusToFahrenheit("32");


When a class is going to work EXACTLY the same consider making the class a static class.


Read Only Instance Field


Read only fields within a class can only have a value applied where the instance is defined or within a constructor.


//Read only field with value applied
public readonly string Address = "123 Main";
 
 
//Constructor that sets value of read only field
public HousePlans(int bedrooms, string address)
{
    this.bedrooms = bedrooms;
    this.Address = address;
}

Once the instance of a class is created, this value cannot be changed. The value of the field can be accessed from an instance of the class.

//Create instance of the HousePlans class.
HousePlans yourHouse = new HousePlans(3, "1000 Capitol");
//Access the read only field
Console.WriteLine(yourHouse.Address);


Attempting to set a value at the instance level will cause an exception.
















Read only fields are used when the value can change from one instance of a class to another but once instaniated the cannot change for the life of the object.

No comments:

Post a Comment