Page Content

Tutorials

C# Structures (Structs) Characteristics And Code Example

C# Structures

C#’s user-defined value types, known as structures, are mostly used to encapsulate small groupings of linked variables. They let you combine related data into a single unit, which should improve code readability and maintainability.

Key Characteristics of Structs

Value Type Semantics: This is the most important feature of structs. The data in structs is directly contained, in contrast to classes, which are reference types.

  • Memory Allocation: Usually, structures are not kept on the heap but rather inline within other objects or on the stack. Because of this, they may be more effective for short-lived, tiny data kinds.
  • Copy on Assignment: A struct creates a copy of all the data when it is provided as a method argument or allocated to another variable. The old copy remains unchanged if the new copy is altered.
  • Non-Nullable by Default: Typically, structures cannot be null. They can, however, be utilised as nullable types (e.g., Vector?).
  • Default Value: Without explicit initialisation, a struct’s fields are automatically set to their default zero values (for example, reference types to null, bool to false, and int to 0).

No Inheritance: It is not possible for a structure to be a base for another type or to inherit from another class or struct. System is their implicit ancestor.ValueType, which is derived from the System.Object. Interfaces can be implemented via structs, though.

Constructors:

  • Structs are unable to declare a default constructor without parameters. One that sets the default values for all fields is automatically provided by the compiler.
  • Constructors with parameters can be declared by structures.

Members: Structs can contain:

  • Methods (but cannot be abstract, virtual, or protected).
  • Properties (like get and set accessors).
  • Get and set accessors are examples of properties.
  • Indexers.
  • Operators (can be overloaded).
  • Events.
  • Nested types.
  • Structs also do not support destructors.

Instantiation: You can instantiate structures with or without the new operator. Until they are individually initialized, the fields stay unassigned if new is not used.

Code Examples

using System;
public class StructExamples
{
    // 1. Simple Struct Declaration
    // Represents a point in 2D space.
    public struct Point2D
    {
        public int X;
        public int Y;
        // 2. Parameterized Constructor
        // Structs can have constructors, but they must take parameters.
        // A parameterless constructor cannot be explicitly defined.
        public Point2D(int x, int y)
        {
            X = x; // Must explicitly assign all fields in constructor
            Y = y;
        }
        // Methods can be defined within a struct
        public void Display()
        {
            Console.WriteLine($"Point: ({X}, {Y})");
        }
        // Overriding ToString() for better display (similar to classes)
        public override string ToString()
        {
            return $"({X}, {Y})";
        }
    }
    public static void Main(string[] args)
    {
        Console.WriteLine("--- Struct Instantiation ---");
        // 3. Instantiation with the 'new' operator
        Point2D p1 = new Point2D(10, 20); // Calls the parameterized constructor
        Console.Write("p1 initialized with new: ");
        p1.Display(); // Output: Point: (10, 20)
        // 4. Instantiation without the 'new' operator
        // Fields must be assigned individually before use.
        Point2D p2;
        p2.X = 30; // Assigning value to field X
        p2.Y = 40; // Assigning value to field Y
        Console.Write("p2 initialized without new: ");
        p2.Display(); 
        // If you try to use fields of p2 before assigning them, it results in a compile-time error.
        // For example: Point2D p3; p3.Display(); // This would cause a compile-time error.
        Console.WriteLine("\n--- Demonstrating Value Type Behavior (Copy on Assignment) ---");
        Point2D originalPoint = new Point2D(5, 5);
        Console.Write("Original Point before copy: ");
        originalPoint.Display(); 
        Point2D copiedPoint = originalPoint; // Value copy occurs here
        Console.Write("Copied Point immediately after copy: ");
        copiedPoint.Display(); 
        // Modify the copied struct
        copiedPoint.X = 100;
        copiedPoint.Y = 200;
        Console.Write("Copied Point after modification: ");
        copiedPoint.Display(); 
        // The original struct remains unchanged because a copy was made
        Console.Write("Original Point after copiedPoint modification: ");
        originalPoint.Display(); 
        Console.WriteLine("\n--- Structs and Default Values ---");
        // A struct variable that is declared but not explicitly assigned will have its fields
        // initialized to their default values (e.g., 0 for int).
        Point2D defaultPoint = default(Point2D); // The default operator 
        Console.Write($"Default Point: {defaultPoint.ToString()} (Values are: {defaultPoint.X}, {defaultPoint.Y})\n");
        // Output: Default Point: (0, 0) (Values are: 0, 0)
        // Attempting to assign null to a struct (will not compile without Nullable<T> or '?')
        // Point2D cannotBeNull = null; // This line would result in a compile-time error
        Console.WriteLine("\n--- Passing Structs to Methods ---");
        // When a struct is passed to a method, a copy is passed, not a reference 
        ChangePoint(originalPoint); // Pass by value
        Console.Write("Original Point after ChangePoint method call: ");
        originalPoint.Display(); 
    }
    // Method to demonstrate passing a struct by value
    public static void ChangePoint(Point2D p)
    {
        p.X = 999;
        p.Y = 999;
        Console.WriteLine($"(Inside ChangePoint) Modified point: ({p.X}, {p.Y})");
    }
}

Output

--- Struct Instantiation ---
p1 initialized with new: Point: (10, 20)
p2 initialized without new: Point: (30, 40)
--- Demonstrating Value Type Behavior (Copy on Assignment) ---
Original Point before copy: Point: (5, 5)
Copied Point immediately after copy: Point: (5, 5)
Copied Point after modification: Point: (100, 200)
Original Point after copiedPoint modification: Point: (5, 5)
--- Structs and Default Values ---
Default Point: (0, 0) (Values are: 0, 0)
--- Passing Structs to Methods ---
(Inside ChangePoint) Modified point: (999, 999)
Original Point after ChangePoint method call: Point: (5, 5)

You can also read Interface In C#(Sharp): Your Code’s Contractual Agreement

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index