Lab: Static#

Objective#

In this lab, we will be working with static members in C#. Specifically, we will modify a Rectangle class to track the number of instances created and to calculate the average area of all created rectangles. Understanding static members and classes will help us better appreciate why they should be avoided.

Provided Code#

Carefully review the provided code. Notice how, currently, there is no mechanism to track the total number of Rectangle instances or perform operations across all instances.

class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }
    public double Area => Width * Height;

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }
}

The Rectangle class provided includes properties for Width and Height, a constructor to set those properties, and a computed, read-only property called Area that computes the area of the rectangle.

Instructions#

Step 1: Introduce a Static Property#

First, introduce add a static property to the Rectangle class to keep track of how many rectangles have been instantiated. You can call it Count and it should have a public get accessor but a private set accessor.

For each Rectangle instance created, increment the static counter field. This will allow us to keep track of how many rectangles have been created.

Here’s what the code should behave like:

new Rectangle(20, 10);
new Rectangle(2, 5);
new Rectangle(10, 12);

Console.WriteLine(Rectangle.Count);
3

🤔 Reflection

Can the class Rectangle be marked as static? Why or why not?

Step 2: Static Constructor Message#

Next, add a static constructor in the Rectangle class that writes a message to the console indicating that the rectangle counter is active.

Here’s what the code should behave like:

new Rectangle(20, 10);
new Rectangle(2, 5);
new Rectangle(110, 12);

Console.WriteLine(Rectangle.Count);
Rectangle counter is now active.
3

Step 3: Array of Rectangles#

Introduce another static field of type Rectangle[]. This static field should be an array that always contains all Rectangles that have been created. You should achieve this by updating the constructor so that it adds the new Rectangle instance to this array.

This should also allow you to refactor the static property called Count, into a computed, read-only property who’s value is computed from the array.

The code should behave like this:

new Rectangle(20, 10);
new Rectangle(2, 5);
new Rectangle(10, 12);

foreach (Rectangle rect in Rectangle.Instances)
    Console.WriteLine($"{rect.Width}x{rect.Height} = {rect.Area}");
Rectangle counter is now active.
20x10 = 200
2x5 = 10
10x12 = 120

Step 4: Computed Read-Only Static Property#

Implement a static property called AverageArea that computes the average area of all rectangles stored in the static array.

The code should behave like this:

new Rectangle(20, 10);
new Rectangle(2, 5);
new Rectangle(10, 12);

Console.WriteLine(Rectangle.AverageArea);
110

Challenge#

Consider how you would write a program to achieve similar functionality without using static members. Before tackling this problem, make sure you understand Object Composition and how it can be used to manage state and behavior among objects.

🤔 Reflection

Reflect on how the use of static members changes the design and functionality of our Rectangle class. What are the limitations and benefits of using static members in this scenario? Can you think of any potential issues with using a static array to store instances?

Hint

To redesigning the solution without static members, consider how an instance of another class might manage multiple Rectangle instances and perform the necessary calculations.