DEV Community

mohamed Tayel
mohamed Tayel

Posted on

Mastering C# Fundamentals: Struct

Meta Description: Discover the key differences between structs and classes in C#. Learn when to use each type, explore practical examples, and understand their memory allocation and use cases. This article also includes assignments to help reinforce your learning with real-world scenarios.

In this topic, we’re exploring structs in C#. The struct keyword allows us to create custom data types that are lightweight and efficient. Structs are ideal for modeling small, simple objects with limited data. Behind the scenes, structs are value types, and they differ from classes in terms of memory allocation and intended use cases. Let’s delve into when and how to use structs effectively in C#.

What is a Struct?

A struct in C# is a value type used to represent small data objects that do not need the overhead of a class. Structs are stored on the stack, making them more efficient for situations where many small instances need to be quickly created and discarded.

Characteristics of Structs:

  • Value Type: Stored on the stack, unlike classes that are stored on the heap.
  • Memory Efficiency: They are lightweight, which makes them suitable for simple objects that are frequently created and discarded.
  • No Inheritance: Unlike classes, structs cannot inherit from other structs or classes but can implement interfaces.
  • Default Initialization: Structs are automatically initialized to their default values without requiring an explicit constructor.

Creating a Struct

To create a struct, we use the struct keyword followed by the name. Here’s an example of a struct to represent a Book, containing information about its title, author, and the number of pages:

struct Book
{
    public string Title;
    public string Author;
    public int Pages;

    // Adding a method to the struct
    public void DisplayBookInfo()
    {
        Console.WriteLine($"Title: {Title}, Author: {Author}, Pages: {Pages}");
    }
}
Enter fullscreen mode Exit fullscreen mode

In this Book struct:

  • We have three fields: Title, Author, and Pages.
  • We also have a method, DisplayBookInfo(), which outputs information about the book.

Using Structs in Code

Now, let’s use the Book struct in a program:

class Program
{
    static void Main()
    {
        // Creating a struct instance
        Book myBook;

        // Initializing fields without using `new`
        myBook.Title = "The Great Gatsby";
        myBook.Author = "F. Scott Fitzgerald";
        myBook.Pages = 180;

        // Calling the method to display book info
        myBook.DisplayBookInfo();  // Output: Title: The Great Gatsby, Author: F. Scott Fitzgerald, Pages: 180

        // Alternatively, you can use `new` to create a struct
        Book anotherBook = new Book
        {
            Title = "1984",
            Author = "George Orwell",
            Pages = 328
        };

        anotherBook.DisplayBookInfo();  // Output: Title: 1984, Author: George Orwell, Pages: 328
    }
}
Enter fullscreen mode Exit fullscreen mode

Differences Between Structs and Classes: When to Use Which?

Structs and classes are both used to create custom types, but they serve different purposes depending on the scenario.

  • Structs are value types and are stored on the stack, which makes them suitable for small, simple objects that do not need the overhead of being referenced. Since structs are stored on the stack, they have faster allocation and deallocation times, making them more efficient for lightweight objects.

  • Classes, on the other hand, are reference types stored on the heap. They are more versatile and are the preferred choice when dealing with complex data structures that need to support features like inheritance, polymorphism, or shared access across various parts of your application.

Use a Struct when:

  • The object is small, contains simple data, and needs efficient memory usage.
  • The object represents a single logical value, such as a point or color.
  • The object will not be modified extensively after being created, and performance is critical.

Use a Class when:

  • The object contains complex behavior, relationships, or needs to share data.
  • You require inheritance or polymorphism to create an object hierarchy.
  • The object's lifecycle is longer or more complex, and it may need to be passed around and modified.

Example: Class vs. Struct

Let’s use an example to illustrate when to use a struct versus a class.

Scenario 1: Using a Struct for a Point in 2D Space

A point in a 2D space is a simple data structure containing X and Y coordinates. It doesn’t have complex behavior or need shared access, so it’s a good candidate for a struct:

struct Point
{
    public int X;
    public int Y;

    public void DisplayPoint()
    {
        Console.WriteLine($"Point: ({X}, {Y})");
    }
}

class Program
{
    static void Main()
    {
        Point p1 = new Point { X = 10, Y = 20 };
        p1.DisplayPoint();  // Output: Point: (10, 20)
    }
}
Enter fullscreen mode Exit fullscreen mode

In this case, struct is preferred because Point is a simple object that requires efficient memory allocation and has no complex behaviors.

Scenario 2: Using a Class for an Employee

Consider an employee object with properties like Name, Department, and Salary. The employee may have methods to calculate bonuses or display employee information, and you may also want to extend the class to create different types of employees (e.g., managers). This is a complex object that may need to be passed around, shared, or modified—making it a good candidate for a class:

class Employee
{
    public string Name { get; set; }
    public string Department { get; set; }
    public decimal Salary { get; set; }

    public void DisplayEmployeeInfo()
    {
        Console.WriteLine($"Name: {Name}, Department: {Department}, Salary: {Salary:C}");
    }
}

class Program
{
    static void Main()
    {
        Employee emp = new Employee
        {
            Name = "Alice Johnson",
            Department = "HR",
            Salary = 50000
        };

        emp.DisplayEmployeeInfo();  // Output: Name: Alice Johnson, Department: HR, Salary: $50,000.00
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, class is the best choice because the employee has complex behaviors and properties that may need to be shared and modified, and you could later create derived classes if needed.

Assignments

Let’s practice what we’ve learned with different levels of assignments.

Level 1: Easy

  1. Create a Struct for a Product Create a struct named Product that contains fields for Name, Price, and Stock. Write a method that displays the product information.
   struct Product
   {
       public string Name;
       public decimal Price;
       public int Stock;

       public void DisplayProductInfo()
       {
           Console.WriteLine($"Product: {Name}, Price: {Price:C}, Stock: {Stock}");
       }
   }

   class Program
   {
       static void Main()
       {
           Product p;
           p.Name = "Laptop";
           p.Price = 1200.50m;
           p.Stock = 25;

           p.DisplayProductInfo();  // Output: Product: Laptop, Price: $1,200.50, Stock: 25
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Print and Modify Product Fields Create another instance of Product, modify its fields, and print the updated information.

Level 2: Medium

  1. Create a Struct for a 2D Rectangle Create a struct named Rectangle that contains fields for Length, Width, and a method to calculate the area. Write another method to display the rectangle's details.
   struct Rectangle
   {
       public double Length;
       public double Width;

       public double CalculateArea()
       {
           return Length * Width;
       }

       public void DisplayRectangleInfo()
       {
           Console.WriteLine($"Rectangle: Length = {Length}, Width = {Width}, Area = {CalculateArea():F2}");
       }
   }

   class Program
   {
       static void Main()
       {
           Rectangle rect;
           rect.Length = 5.0;
           rect.Width = 10.0;

           rect.DisplayRectangleInfo();  // Output: Rectangle: Length = 5, Width = 10, Area = 50.00
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Add Perimeter Calculation Method Extend the Rectangle struct to add a method to calculate and display the perimeter of the rectangle.

Level 3: Difficult

  1. Create a Class Representing a Car Create a class named Car with properties Make, Model, and Mileage. Add methods to Drive the car (increasing mileage) and Display Car Details. This class should demonstrate the use of a complex object.
   class Car
   {
       public string Make { get; set; }
       public string Model { get; set; }
       public int Mileage { get; private set; }

       public void Drive(int miles)
       {
           if (

miles > 0)
           {
               Mileage += miles;
               Console.WriteLine($"{Model} driven for {miles} miles. Total mileage is now {Mileage} miles.");
           }
       }

       public void DisplayCarDetails()
       {
           Console.WriteLine($"Car: Make = {Make}, Model = {Model}, Mileage = {Mileage} miles");
       }
   }

   class Program
   {
       static void Main()
       {
           Car car = new Car
           {
               Make = "Toyota",
               Model = "Camry",
               Mileage = 15000
           };

           car.DisplayCarDetails();  // Output: Car: Make = Toyota, Model = Camry, Mileage = 15000 miles
           car.Drive(500);           // Output: Camry driven for 500 miles. Total mileage is now 15500 miles.
           car.DisplayCarDetails();  // Output: Car: Make = Toyota, Model = Camry, Mileage = 15500 miles
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Extend Car Functionality Add methods to Service the car, which could involve resetting mileage intervals for services. Implement an interface for additional behavior, such as IServicable.

Conclusion

Structs and classes in C# both serve to create custom data types, but they differ in terms of use case and memory allocation. Structs are value types and are best for small, simple objects that don’t need shared references, while classes are reference types and are preferred for more complex, shared objects with behavior that may change over time.

By practicing these assignments, you'll gain hands-on experience that helps to understand the best times to use structs versus classes, and how each can be effectively used in C#.

Top comments (0)