Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

ความแตกต่างระหว่าง Class และ Struct ใน C#

ความแตกต่างหลัก: Reference Type vs Value Type

คุณสมบัติClass (Reference Type)Struct (Value Type)
Memory AllocationHeap (Managed Heap)Stack (หรือ Inline ใน Containing Type)
AssignmentCopy Reference (Point to Same Object)Copy Value (Deep Copy)
Nullสามารถเป็น Null ได้ไม่สามารถเป็น Null ได้ (Nullable Struct: T?)
Default ValuenullZero-initialized (ทั้ง Struct)
Inheritanceรองรับ (Single Inheritance)ไม่รองรับ (Implicitly Sealed)
InterfacesImplement ได้Implement ได้
Destructor/Finalizerมีได้ (~Class())ไม่มี
ConstructorParameterless + ParameterizedParameterized เท่านั้น (C# 10+ มี Parameterless)
protected Modifierใช้ได้ใช้ไม่ได้
Field Initializersได้ไม่ได้ (C# 10-)
PerformanceHeap Alloc, GC Pressure, IndirectionNo Heap, No GC, Cache Friendly

ตัวอย่างพฤติกรรม Assignment


class RefClass { public int Value; }
struct ValStruct { public int Value; }

class Program
{
    static void Main()
    {
        // Class - Reference Semantics
        RefClass rc1 = new RefClass { Value = 10 };
        RefClass rc2 = rc1; // Copy Reference
        rc2.Value = 20;
        Console.WriteLine($"rc1: {rc1.Value}, rc2: {rc2.Value}"); // 20, 20 (Same Object!)
        
        // Struct - Value Semantics
        ValStruct vs1 = new ValStruct { Value = 10 };
        ValStruct vs2 = vs1; // Copy Value
        vs2.Value = 20;
        Console.WriteLine($"vs1: {vs1.Value}, vs2: {vs2.Value}"); // 10, 20 (Independent!)
    }
}

Output

rc1: 20, rc2: 20
vs1: 10, vs2: 20

เมื่อไหร่ควรใช้ Struct

  • ✅ Small Data (≤ 16 bytes / 4 Fields ประมาณ)
  • ✅ Immutable Data (Coordinate, DateTime, Guid, Money)
  • ✅ High Volume (Arrays, Collections - No GC Pressure)
  • ✅ Performance Critical (Game, Math, Graphics)
  • ✅ Value Semantics ทางตรรกะ (Equality = Value Equality)

เมื่อไหร่ควรใช้ Class

  • ✅ Large Data / Complex Object
  • ✅ Mutable Reference Semantics (Identity สำคัญ)
  • ✅ Need Inheritance / Polymorphism
  • ✅ Need Null Representation
  • ✅ Reference Equality (Identity) สำคัญ
  • ✅ Framework Design Guidelines: Default เป็น Class

Struct Best Practices (C# 7.2+)


// readonly struct - Immutable Guarantee
public readonly struct Point3D
{
    public double X { get; init; }
    public double Y { get; init; }
    public double Z { get; init; }
    
    public Point3D(double x, double y, double z) => (X, Y, Z) = (x, y, z);
    
    // Method ไม่ Mutate State
    public double DistanceFromOrigin() => Math.Sqrt(X*X + Y*Y + Z*Z);
    
    // with-expression (C# 9+) สำหรับ "Mutation"
    public Point3D WithX(double newX) => this with { X = newX };
}

// ref struct - Stack Only (Span-like)
public ref struct StackOnly
{
    public Span<byte> Buffer;
    // ไม่สามารถเป็น Field ของ Class, ใช้ใน Stack เท่านั้น
}

Boxing/Unboxing Cost


struct Point { public int X, Y; }

Point p = new Point { X = 1, Y = 2 };
object o = p;        // Boxing: Heap Alloc + Copy
Point p2 = (Point)o; // Unboxing: Copy Back

// Generic ใช้ Struct ได้โดยไม่ Boxing
List<Point> points = new(); // No Boxing
List<object> objects = new(); 
objects.Add(p); // Boxing!

C# 10+ Struct Enhancements

  • Parameterless Constructor: public Struct() { }
  • Field Initializers: public int X = 5;
  • record struct - Value-based Equality, With-expression
  • readonly record struct - Immutable

// C# 10+ Record Struct
public readonly record struct Point(int X, int Y)
{
    public double Distance => Math.Sqrt(X*X + Y*Y);
}

// Usage
var p1 = new Point(3, 4);
var p2 = p1 with { X = 5 }; // p2 = (5, 4)
Console.WriteLine(p1 == p2); // False (Value Equality)