What is Structure in C#.NET [Explained With Examples]

In the context of C#.NET, structure, or struct, is a value type data structure. It is used to encapsulate a small group of related variables, such as the coordinates of a rectangle or the characteristics of an item in an inventory. Unlike classes, which are reference types, structures are stored on the stack, which can provide performance benefits. Since structures are value types, each instance holds its own copy of the data, and operations on one instance do not affect other instances.

To demonstrate the use of a structure in C#.NET, consider an example where there is a need to represent a simple 2D point. The structure Point might contain two integer variables, X and Y, to represent the coordinates. The following code defines a Point structure in C#:

struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

With this definition, a Point structure can be created and used in a C#.NET program as follows:

Point p1 = new Point(0, 0);
Point p2 = new Point(10, 20);

Console.WriteLine($"Point 1: ({p1.X}, {p1.Y})");
Console.WriteLine($"Point 2: ({p2.X}, {p2.Y})");

This code creates two Point instances with different coordinates and prints them to the console. The independence of each instance’s data is a key characteristic of structures in C#.NET.

Understanding Structures in C#.NET

In C#.NET, a structure, often referred to as a struct, is a value-type data structure. It enables the encapsulation of related variables into a single entity. While similar to classes, structures are more suitable for small data constructs that do not require inheritance and extensive functionality.

Key Attributes of Structures in C#.NET:

  • Value-Type: Structs are stored on the stack, leading to faster access compared to reference types.
  • Initialization: Unlike classes, structs can be instantiated without using the new operator.
  • No Inheritance: They cannot inherit from other structs or classes.
  • Interfaces: However, structs can implement interfaces.

Structure Declaration:

To declare a structure in C#.NET:

struct Book
{
    public string title;
    public string author;
    public int code;
}

Usage Example:

Book myBook;
myBook.title = "The C# Programming Language";
myBook.author = "A. Programmer";
myBook.code = 123456;

In this example, myBook is a struct instance with fields title, author, and code.

Structures should be considered when one requires an efficient lightweight object that doesn’t need a class’s full features. They are extensively used in scenarios where performance is critical and overhead needs to be minimized.

Defining a Structure in C#

In C#/.NET, structures are value types that encapsulate data and related functionalities. They are defined using the struct keyword and are best suited for small data structures that contain mainly data that is not intended to be modified after creation.

Syntax of a Structure

The syntax to define a structure in C# is straightforward:

struct StructureName
{
    // members
}

A structure is declared using the struct keyword followed by an identifier, StructureName, and a body enclosed in curly braces. Within these braces, one can declare members of the structure.

Structure Members

A structure can contain the following members:

  • Fields: Variables of any type that hold data.
  • Methods: Functions that define actions.
  • Properties: Mechanisms to get and set field values in a controlled manner.
  • Constructors: Special methods called at the time of object creation.
  • Events: Notifications that a structure can send out to signify an action has occurred.

For example:

public struct RGBColor
{
    public int Red;
    public int Green;
    public int Blue;

    public RGBColor(int r, int g, int b)
    {
        Red = r;
        Green = g;
        Blue = b;
    }

    public void DisplayColor()
    {
        Console.WriteLine($"Red: {Red}, Green: {Green}, Blue: {Blue}");
    }
}

In this example, RGBColor is a structure holding three fields (Red, Green, Blue) and has a constructor and a method (DisplayColor). Structures can be instantiated and used just like other value types in C#.

Here is a complete example:

using System;

public struct RGBColor
{
    public int Red;
    public int Green;
    public int Blue;

    public RGBColor(int r, int g, int b)
    {
        Red = r;
        Green = g;
        Blue = b;
    }

    public void DisplayColor()
    {
        Console.WriteLine($"Red: {Red}, Green: {Green}, Blue: {Blue}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Creating an instance of RGBColor
        RGBColor color = new RGBColor(255, 100, 50);

        // Displaying the color
        color.DisplayColor();
    }
}

Using Structures in Code

In C#.NET, structures are value types used to encapsulate small groups of related variables. They’re particularly useful when one wants to define a complex data point without the overhead of a class.

Creating Structure Instances

To instantiate a structure, one typically uses the new keyword, just as with classes. However, structures also allow for direct instantiation without new, by simply assigning values to its members.

Example:

// Define a structure
public struct Point
{
    public int X;
    public int Y;
}

// Instantiate with new
Point p1 = new Point { X = 1, Y = 2 };

// Direct instantiation
Point p2;
p2.X = 3;
p2.Y = 4;

Accessing Structure Members

Once a structure is instantiated, accessing its members is straightforward. They can be accessed using the dot (.) operator, allowing one to retrieve or modify the values stored within the structure.

Example:

// Continuing from the previous code

// Access and modify members
p1.X = 10;
p1.Y = 20;

// Accessing members to use in expressions
int area = p1.X * p1.Y;

Structures vs Classes in C#

In C#.NET, structures (structs) and classes are both constructs for creating new types, but they serve different purposes and have specific use-case scenarios.

Similarities to Classes

  • Definition: Both structs and classes can have constructors, methods, fields, properties, and events.
  • Syntax: They share similar syntax for defining members and accessibility levels.

Differences from Classes

  • Storage: Structs are value types stored on the stack, while classes are reference types stored on the heap.
  • Inheritance: Classes support inheritance, allowing them to extend other classes. Structs cannot inherit from other structs or classes.
  • Instantiation: Objects of a class must be instantiated with new. Structs can be instantiated without new, which defaults the member values.
  • Default Constructor: Structs always have a parameterless constructor that can’t be overridden. Classes may define a custom parameterless constructor.
  • Nullability: Reference types (classes) can be null. Value types (structs) cannot be null unless they are defined as nullable (Nullable<T> or T? for short).

Examples of C# Structures

In C#, structures are value types that can encapsulate data and related functionality. They make code more modular and understandable. Structures are particularly useful for small data structures that have semantic meaning and do not require inheritance.

Basic Example

A basic example of a structure in C# is defining a point in a two-dimensional space.

public struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

Here, Point collects two integers, X and Y, representing the coordinates in a Cartesian plane.

Complex Example

For a more complex scenario, consider a structure that represents a Rectangle. It includes properties for location, size, and methods for area and perimeter calculation.

public struct Rectangle
{
    public Point Location;
    public int Width;
    public int Height;

    public Rectangle(Point location, int width, int height)
    {
        Location = location;
        Width = width;
        Height = height;
    }

    public int Area()
    {
        return Width * Height;
    }

    public int Perimeter()
    {
        return 2 * (Width + Height);
    }
}

In this example, Rectangle integrates a Point structure for location and adds size properties along with methods to compute the area and perimeter, showcasing the capability of structures to manage more complex data.

Best Practices for Using Structures

When using structures (struct) in C#, adhering to these best practices promotes efficiency and clarity:

  • Initialization: Always initialize structures to avoid working with unassigned fields. This ensures type safety and predictable behavior. struct Point { public int X, Y; } Point p = new Point { X = 0, Y = 0 };
  • Immutability: Making structures immutable—by not allowing the state to change after creation—can enhance performance, especially when working with collections. public readonly struct ImmutablePoint { public int X { get; } public int Y { get; } public ImmutablePoint(int x, int y) { X = x; Y = y; } }
  • Size Consideration: Structures should be small (ideally less than 16 bytes) since larger structures can reduce performance due to copying costs when passed by value.
  • Interfaces: Be cautious when implementing interfaces on structures. Doing so can lead to boxing and unboxing, negating the value-type performance benefits.
  • Equality: Override Equals and GetHashCode to provide value-based equality semantics, thereby avoiding reflection-based comparisons. public override bool Equals(object obj) { if (obj is Point other) { return X == other.X && Y == other.Y; } return false; } public override int GetHashCode() { return HashCode.Combine(X, Y); }
  • Practicality: Use structures when there is a clear advantage in terms of performance and memory footprint, but prefer classes when the data structure is complex or contains reference-type members.

Advanced Topics

The advanced topics cover the nuances of structures when considering inheritance limitations and the implications of boxing and unboxing on performance and type safety.

Inheritance and Structures

In C#, structures, defined by the struct keyword, are value types and hence cannot participate in inheritance. They do not support inheritance like classes do, which are reference types. Structures can, however, implement interfaces to ensure a contract-based design for the methods they expose. For example, a struct Point could implement IComparable to allow comparison with other Point instances.

public struct Point : IComparable<Point>
{
    public int X { get; set; }
    public int Y { get; set; }

    public int CompareTo(Point other)
    {
        // Compare by X, then by Y.
        if (this.X == other.X)
        {
            return this.Y.CompareTo(other.Y);
        }
        return this.X.CompareTo(other.X);
    }
}

Boxing and Unboxing

Boxing is the process of converting a value type to a reference type, encapsulating the value inside an object instance. Unboxing is the inverse, extracting the value type from the object. Both boxing and unboxing can impact performance due to additional overhead.

  • Boxing Example: int number = 123; object boxed = number; // Boxing
  • Unboxing Example: int unboxed = (int)boxed; // Unboxing

Care must be taken to minimize unnecessary boxing and unboxing operations since they involve memory allocation and can lead to increased garbage collection pressure.

Conclusion

In C#, structures, also known as structs, are value-type data containers used for grouping related variables. Unlike classes, which are reference types, structures are lighter and can be beneficial when high performance is necessary, particularly in systems with limited resources.

Structures should be utilized when there is a need for a small data structure that has value semantics. They allow the grouping of variables under one name for a logical representation of a concept or an entity. This can lead to more maintainable and readable code.

A common use case for structures is mathematical computations where complex numbers or points in a coordinate system are involved. Here, structures can be defined to group a pair of numbers and provide methods that operate on the data.

public struct Point {
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y) {
        X = x;
        Y = y;
    }

    public void Translate(int dx, int dy) {
        X += dx;
        Y += dy;
    }
}

In the example above, the Point struct is composed of X and Y integers with a method Translate to change the point’s position. Clients of the structure can expect consistent performance, as instances are copied when passed around, reducing the risk of side effects.

Choosing between a class and a struct must be a careful consideration, guided by the size of data being handled, the necessity for inheritance, and whether it makes sense for the entity to have identity semantics. When employed correctly, structures contribute to efficient and type-safe code.

In this C# tutorial, I have explained to you how to work with Structure in C#.NET with a few examples.

You may also like: