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
, orprotected
). - Properties (like
get
andset
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