The this Keyword, Static and Instance Members
AAHC

Click on A to make all fonts on the page smaller.

Click on A to make all fonts on the page larger.

Click on HC to toggle high contrast mode. When you move your mouse over some bold words in high contrast mode, related words are automatically highlighted. Text is shown in black and white.


In this lesson, we'll revisit the topic of class instances and the this keyword, and cover the concept of static properties, methods, and classes.

Class Instances
Instances

By now, you've had numerous opportunities to create classes, and then create instances of the classes. When you use the new keyword, you are creating a class instance. What exactly is a class instance? When you create a class instance, that object exists in memory on the memory heap. Each class instance resides in its on unique memory space. As we've learned, classes are composed of variables and class functions (methods, accessors, etc). As you create multiple class instances, class variables must be unique on a per-class instance basis. So, if you created hundreds of instances of the same class, you would have hundreds of unique versions of each class variable.

What about programming code? Do we need multiple copies of the code? No, we do not, so class functions are only stored once. If you're interested in where in memory the single code copy resides, that's not as straightforward to answer. Before our C# code can execute, it needs to be compiled. The .NET architecture employs a mechanism known as Just In Time (JIT) compilation to compile the code, and keeps the compiled code available should it be needed. This compiled code doesn't remain indefinitely, so it's possible that the class functions are essentially not in memory. When they are finally compiled, they're kept in what is typically referrned to as a code memory segment, a space reserved for code. Effectively, you can think of this memory as a dynamic code heap.

What does this notion of a class instance mean to us as C# OOP programmers? As we've learned so far, if we want to use a class, we have to create an instance of that class. Using public class functions or fields (public class variables), we can access and utilize our class instance.

Self-Referencing Using the 'this' Keyword

You may already be familiar with the this keyword. Many new OOP programmers have trouble understanding what this stands for and how to use it. Let's dive in.

The this keyword is only used within a class, and effectively refers to the class instance. What does that mean? From within a class, whenever you want to access class instance members, you use this. If the class instance member name is unique, then you can omit the this keyword. There are times, though, when you must use it, as we'll discuss next. So, when you see the this keyword, remember that this represents the current class instance.

When is using this optional, and when is it required? Below are the most common circumstances (we'll refer back to these numbers later):

  1. May Use: To clarify the code refers to a class instance member.
  2. Must Use: To qualify class instance members that would otherwise be hidden by other items of the same name, known as shadowing.
  3. Must Use: When passing the instance object itself as a parameter to a method.
  4. Must Use: When returning an instance object itself from a method.
  5. Must Use: When passing parameters between class constructors, known as constructor chaining.
  6. Must Use: To declare class indexers (discussed in a later lesson).
  7. Must Use: To declare class extension methods (discussed in a later lesson).
Coding: Boxing

Let's create a project to experiment with the this keyword and classes.

Select File | New | Project. Change the project name to Boxing and click OK.

Click the entry for Form1.cs and change it to Boxing.cs. Change the form title bar's Text property in the Properties Window to Boxing. Click to save your changes.

Modify the form to look like this:

Change each control's Name property to match the Name Property column, and Text property to match the Text Property column, below. When you finish, click to save your changes.

ObjectName PropertyText Property
ListBoxboxingListBox 
ButtonboxingButtonBox It
ButtoncloseButtonClose

Add event handlers for the boxingButton and closeButton controls by double-clicking on each control to automatically generate the default event handler code. Studio generates an appropriate name for the event handler that consists of the name of the control, an underscore separator, and the event name.

Modify the Boxing.cs code as shown below. The event handler code was added previously.

Boxing.cs
using ...

namespace Boxing
{
    public partial class Boxing : Form
    {
        public Boxing()
        {
            InitializeComponent();
        }
        
        private void boxButton_Click(object sender, EventArgs e)
        {
        }
        
        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

As you can see, all we added was the code to close the form when the closeButton is clicked. Let's next add a couple of new classes.

Right-click on the Boxing project item in the Solution Explorer, and select Add | Class.... In the Add New Item dialog box, change the Name from Class1.cs to Box.cs, then click Add.

In the Box.cs Code Editor, modify the code as shown:

Box.cs
using ...

namespace Boxing
{
    class Box
    {
        // Automatic class properties.
        public double Length { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        
        // Typical constructor used with double, double, double fingerprint.
        public Box(double Length, double Width, double Height)
        {
            this.Length = Length;
            this.Width = Width;
            this.Height = Height;
        }
        
        // Default constructor, using this to call constructor with double, double, double fingerprint,
        // Note using explicit 0.0 double literal to prevent any forced type conversions, and 
        // placing empty method body curly braces on same line to conserve space
        public Box() : this(0.0, 0.0, 0.0) { }
        
        // Private constructor that takes a Box as a parameter, used to clone itself.
        private Box(Box Box) : this(Box.Length, Box.Width, Box.Height) {}
        
        // A method to return a cloned version of the current Box.
        // Note that cloning is rarely this simple!
        public Box Clone() { return new Box(this); }
            
        // Calculate volume of box.
        public double Volume()
        {
            return this.Length * this.Width * this.Height;
        }
    }
}

Click to save your changes. Before running or explaining this code, we'll also add the code that will use the Box class.

In the Boxing.cs Code Editor, modify the code as shown:

Boxing.cs
using ...

namespace Boxing
{
    public partial class Boxing : Form
    {
        public Boxing()
        {
        InitializeComponent();
        }
        
        private void boxingButton_Click(object sender, EventArgs e)
        {
            // Fun with Box.
            boxingListBox.Items.Add("Creating box...");
            Box box = new Box(5, 10, 15);
            boxingListBox.Items.Add("Cloning box as newBox...");
            Box newBox = box.Clone();
            boxingListBox.Items.Add("Do box and newBox reference same object? " + ReferenceEquals(box, newBox));
            boxingListBox.Items.Add("Setting box to null...");
            box = null;
            boxingListBox.Items.Add("Is box null? " + (box == null));
            boxingListBox.Items.Add("Is newBox null? " + (newBox == null));
            boxingListBox.Items.Add("Volume : " + newBox.Volume());
        }
        
        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

Click to save, and to run the program. Click Box It to see the results:

Click Close to close the form. Now let's discuss how it works.

Box.cs
using ...

namespace Boxing
{
    class Box
    {
        // Automatic class properties.
        public double Length { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        
        // Typical constructor used with double, double, double fingerprint.
        public Box(double Length, double Width, double Height)
        {
            this.Length = Length; [2]
            this.Width = Width; [2]
            this.Height = Height; [2]
        }
        
        // Default constructor, using this to call constructor with double, double, double fingerprint,
        // Note using explicit 0.0 double literal to prevent any forced type conversions, and 
        // placing empty method body curly braces on same line to conserve space
        public Box() : this(0.0, 0.0, 0.0) { } [5]
        
        // Private constructor that takes a Box as a parameter, used to clone itself.
        private Box(Box Box) : this(Box.Length, Box.Width, Box.Height) {} [5]
        
        // A method to return a cloned version of the current Box.
        // Note that cloning is rarely this simple!
        public Box Clone() { return new Box(this); } [3]
            
        // Calculate volume of box.
        public double Volume()
        {
            return this.Length * this.Width * this.Height; [1]
        }
    }
}

As you examine this code, note the different uses of the this keyword, the Box class, and the constructors. Also, review the different ways we listed that you can use the this keyword. We've added numbers marked in [red] that relate to the numbers listed above to help you recognize which this usage is represented by the particular code. In our code so far, we've illustrated: [1], using this to clarify that a referenced variable is a class variable; [2], to prevent shadowing; [3], passing this as a method parameter; and [5], constructor chaining. We'll illustrate 4 in another class shortly.

Next, let's analyze the code in the boxingButton_Click event handler in Boxing.cs.

Boxing.cs
.
.
.
        private void boxingButton_Click(object sender, EventArgs e)
        {
            // Fun with Box.
            boxingListBox.Items.Add("Creating box...");
            Box box = new Box(5, 10, 15);
            boxingListBox.Items.Add("Cloning box as newBox...");
            Box newBox = box.Clone();
            boxingListBox.Items.Add("Do box and newBox reference same object? " + ReferenceEquals(box, newBox));
            boxingListBox.Items.Add("Setting box to null...");
            box = null;
            boxingListBox.Items.Add("Is box null? " + (box == null));
            boxingListBox.Items.Add("Is newBox null? " + (newBox == null));
            boxingListBox.Items.Add("Volume : " + newBox.Volume());
        }
.
.
.

The code to add items to a ListBox should be familiar by now. First, we create a Box instance, then declare a second Box variable, using the Clone method to create a copy of our first instance and setting our second Box variable to this cloned reference. We then test to see if both of the Box variables refer to the same object in memory using the ReferenceEquals method. When you run the code, you'll see that both Box variables do not reference the same memory location, so we know that our cloning created two separate instance objects.

Next, we set our first Box instance to null, effectively de-referencing the variable. Remember, .Net tracks references to objects, and when all references are removed, that memory is marked for deletion and will eventually be recovered by the Garbage Collector. Setting an instance variable to null removes that reference. We confirm that our first instance variable is null, and confirm that despite removing the first reference, the second instance variable is not null. Finally, we calculate and display the volume of our cloned Box.

Let's add a second class so we can illustrate 4, returning this from a method.

Right-click on the Boxing project item in the Solution Explorer, and select Add | Class.... In the Add New Item dialog box, change the Name from Class1.cs to SquareBox.cs, then click Add.

In the SquareBox.cs Code Editor, modify the code as shown below.

SquareBox.cs
using ...

namespace Boxing
{
    class SquareBox
    {
        // Box field.
        public Box Box;
        
        // Automatic property for single dimension value (length, width and height are all the same).
        public double Dimension { get; set; }
        
        // Constructor with double fingerprint.
        // Note that we use this constructor to create our Box object.
        public SquareBox(double Dimension)
        {
            this.Box = new Box(Dimension, Dimension, Dimension);
            this.Dimension = Dimension;
        }
        
        // Default constructor, calls constructor with double fingerprint, passing double literal,
        // using space-conserving method body coding convention.
        public SquareBox() : this(0.0) { }
        
        // Return a reference to the current object.
        public SquareBox Reference()
        {
            return this;
        }
    }
}

Now let's also add the code that will use the SquareBox class.

Select the Boxing.cs Code Editor, and modify the code as shown:

Boxing.cs
using ...

namespace Boxing
{
    public partial class Boxing : Form
    {
        public Boxing()
        {
        InitializeComponent();
        }
        
        private void boxButton_Click(object sender, EventArgs e)
        {
            // Fun with Box.
            boxingListBox.Items.Add("Creating box...");
            Box box = new Box(5, 10, 15);
            boxingListBox.Items.Add("Cloning box as newBox...");
            Box newBox = box.Clone();
            boxingListBox.Items.Add("Do box and newBox reference same object? " + ReferenceEquals(box, newBox));
            boxingListBox.Items.Add("Setting box to null...");
            box = null;
            boxingListBox.Items.Add("Is box null? " + (box == null));
            boxingListBox.Items.Add("Is newBox null? " + (newBox == null));
            boxingListBox.Items.Add("Volume : " + newBox.Volume());
            
            // Fun with SquareBox.
            boxingListBox.Items.Add(""); // Empty line
            boxingListBox.Items.Add("Creating squareBox...");
            SquareBox squareBox = new SquareBox(20);
            SquareBox newSquareBox = squareBox.Reference();
            boxingListBox.Items.Add("Do squareBox and newSquareBox reference same object? " + ReferenceEquals(squareBox, newSquareBox));
            boxingListBox.Items.Add("Setting squareBox to null...");
            squareBox = null;
            boxingListBox.Items.Add("Is squareBox null? " + (squareBox == null));
            boxingListBox.Items.Add("Is newSquareBox null? " + (newSquareBox == null));
        }
        
        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

Click and to run the program. Click Box It to see the results:

Click Close to close the form. Let's discuss how it works.

SquareBox.cs
using ...

namespace Boxing
{
    class SquareBox
    {
        // Box field.
        public Box Box;
        
        // Automatic property for single dimension value (length, width and height are all the same).
        public double Dimension { get; set; }
        
        // Constructor with double fingerprint.
        // Note that we use this constructor to create our Box object.
        public SquareBox(double Dimension)
        {
            this.Box = new Box(Dimension, Dimension, Dimension); [1]
            this.Dimension = Dimension; [2]
        }
        
        // Default constructor, calls constructor with double fingerprint, passing double literal,
        // using space-conserving method body coding convention.
        public SquareBox() : this(0.0) { } [5]
        
        // Return a reference to the current object.
        public SquareBox Reference()
        {
            return this; [4]
        }
    }
}

Again, note the different uses of the this keyword, the SquareBox class, and the constructors. Again review the different ways we listed that you can use the this keyword. We've again added numbers marked in [red] to help you recognize which this usage is represented by the particular code. In the SquareBox class code, we've again illustrated [1], using this to clarify that a referenced variable is a class variable; [2], to prevent shadowing; and [5], constructor chaining; and we've added [4], returning the instance object itself from a method.

Next, let's analyze the code in the boxingButton_Click event handler in Boxing.cs that relates to using the SquareBox class.

Boxing.cs
.
.
.
        private void boxingButton_Click(object sender, EventArgs e)
        {
            .
            .
            .
            
            // Fun with SquareBox.
            boxingListBox.Items.Add(""); // Empty line
            boxingListBox.Items.Add("Creating squareBox...");
            SquareBox squareBox = new SquareBox(20);
            SquareBox newSquareBox = squareBox.Reference();
            boxingListBox.Items.Add("Do squareBox and newSquareBox reference same object? " + ReferenceEquals(squareBox, newSquareBox));
            boxingListBox.Items.Add("Setting squareBox to null...");
            squareBox = null;
            boxingListBox.Items.Add("Is squareBox null? " + (squareBox == null));
            boxingListBox.Items.Add("Is newSquareBox null? " + (newSquareBox == null));
        }
.
.
.

Our Boxing.cs code to test the SquareBox class is almost identical to the code we used for the Boxing class but this time, rather than try to clone, or make a copy of, our object, we create a reference to our object. When we test to see if both instance variables reference the same object in memory, we find out that they do indeed reference the same object. When we set the first instance variable to null, we get the same results as before, but should we have? Would you have expected that, because we set the first instance variable to null, we would somehow be deleting the object in memory? Setting the instance variable to null only de-references that instance variable, so the second instance variable continues to reference the same memory location.

Static Members and Classes
Static Keyword

Now that we've revisited class instances, and discussed the this keyword as a reference to members of a current class instance, we can talk about static members and classes. The term static generally refers to something that doesn't change, and in the context of many other computer languages, that's part of the meaning, but in C#, the meaning and usage is reserved to work explicitly with class members and class definitions. In short, the static keyword qualifies class members and classes for usage without the need to create an instance of the class. From an OOP perspective, static members are used to separate data and behavior that is independent from whatever might happen to an object (class instance).

NoteIf you research the term static online, you may come across the original usage of static in other computer languages: static variables. C# does not support method-level static variables, only class-level static variables.

Class Instances Versus Static Instances

So, what does independence from a class instance mean? Typically, we create a class instance, and then reference the class members using the class instance variable and the dot notation, as shown below. However, if a property or method is defined as static, you do not need the class instance variable (also shown below):

Class Instances Versus Static Instances
// Class instance
SquareBox squareBox = new SquareBox();
squareBox.Dimension = 25;

// Static instance
int numberOfDimensions = SquareBox.Dimensions;

In the example above, the SquareBox reference is not a reference to a class instance, but instead a reference to the class itself. We do not need to create an instance of the SquareBox class to reference the Dimensions property (note that the word is plural and would return 3, as a square box has three physical dimensions: length, width, and height). Below is a sample of how we would define a SquareBox class using the static keyword to create the C# Dimensions read-only automatic property (we're making the assumption that in our dimension, physical objects only have three dimensions, although sci-fi fans may disagree).

Static Class Property
public class SquareBox
{
    // Define the static property Dimensions.
    public static int Dimensions { get { return 3; } private set { } }
}                

NoteThe creation of a static read-only automatic property for Dimensions is a bit contrived, as we could just as easily have created a constant. Nevertheless, you should note that we did deviate from our earlier statement about when to use an automatic property: when you do not need additional coding. If you simply want to return a value, or perform other types of operations that will not involve the property name, you can add a method body to either the get or the set; however, you must either provide no method bodies, or both method bodies, even if the method body is empty, as is the case with the set for Dimensions above.

We can add static to any property, or method, in a class definition. Here's an example of a static method.

Static Class Method
public class SquareBox
{
    // Define the static method VolumeCalculation
    public static string VolumeCalculation()
    {
        return "Length x Width x Height"; 
    }
}                

Just as with a static property, we can call a static method by referencing the class:

Calling a Static Class Method
string volumeCalculation = SquareBox.VolumeCalculation();                

Classes can also include a static constructor. A static constructor could be used to initialize static fields in a class. A static constructor is called before an instance of a class is created, and before a static member function is called or accessed. A static constructor is only ever called once. Also, static constructors do not have an access modifier:

Static Class Method
public class SquareBox
{
    public static int Dimensions { get; private set; }
    
    // Define the static constructor to initialize the static property
    static SquareBox()
    {
        // Note that you can not use this with Dimensions, as we are not using a reference to an instance
        Dimensions = 3;
    }
}                

NoteWhen accessing static class members, you cannot use the this keyword. Why? The this keyword is an instance reference variable, but with a static class member, we are not accessing the class instance.

We can create a static class. A static class cannot be instantiated. When you create a static class, any method or property that you want to make available via a static reference to the class must also be prefixed with the static keyword, as shown below.

Static Class with Static Method and Field
static class Volumes
{
    public static string Description = "Volume Calculations";
    
    public static string BoxVolumeCalculation()
    {
        return "Length x Width x Height"; 
    }
    
    public static string SphereVolumeCalcuation()
    {
        return "4/3 * PI * (radius * radis * radius)";
    }
}

So that's how we use the static keyword. You'll have a chance to code using static in this lesson's homework project.

Before you move on to the next lesson, do your homework! Right-click in the window where this lesson text appears and select Back. Then select Quiz for this lesson in the syllabus and answer the quiz questions. When you finish the quiz questions, click HAND IT IN at the bottom of that window. Then do the same with the Project(s) for the lesson. Your instructor will grade your quiz(zes) and project(s) and provide guidance if needed.