مقدمه

ما به طور طبیعی از عملگرهایی مانند `+`، `-` یا `==` برای کار با انواع داده‌ی پایه‌ای مثل int و double استفاده می‌کنیم. برای مثال، عبارت 5 + 10 کاملاً قابل فهم است. اما اگر بخواهیم دو شیء از نوع سفارشی خودمان (مثلاً دو شیء از کلاس Point که نماینده‌ی یک نقطه در فضا هستند) را با هم جمع کنیم چه؟ به طور پیش‌فرض، کامپایلر نمی‌داند چگونه عملگر `+` را بر روی این اشیاء اعمال کند. سربارگذاری عملگر (Operator Overloading) ویژگی قدرتمندی در C# است که به ما اجازه می‌دهد تا پیاده‌سازی سفارشی خود را برای عملگرهای استاندارد تعریف کنیم. این کار باعث می‌شود که انواع داده‌ی سفارشی ما رفتاری طبیعی‌تر و شبیه به انواع داده‌ی داخلی زبان داشته باشند و کد ما خواناتر شود.

سربارگذاری عملگرها چیست؟

سربارگذاری عملگر به معنای تعریف یک متد استاتیک ویژه در کلاس یا ساختار است که به کامپایلر می‌گوید هنگام مواجهه با یک عملگر خاص بر روی اشیاء آن نوع، چه کاری باید انجام دهد. در واقع، این یک نوع "شکر نحوی" (syntactic sugar) است که به جای فراخوانی یک متد با نامی مانند Add(p1, p2) به ما اجازه می‌دهد تا به سادگی بنویسیم p1 + p2. این کار باعث می‌شود کدی که با مفاهیم ریاضی یا فیزیکی (مانند بردارها، ماتریس‌ها یا اعداد مختلط) سروکار دارد، بسیار تمیزتر و شبیه‌تر به فرمول‌های اصلی شود.

نحوه‌ی سربارگذاری یک عملگر

برای سربارگذاری یک عملگر، باید یک متد public static در کلاس یا ساختار خود تعریف کنید. این متد از کلمه‌ی کلیدی operator و به دنبال آن، خودِ عملگری که می‌خواهید سربارگذاری کنید، استفاده می‌کند. بیایید یک ساختار Point بسازیم و عملگر `+` را برای آن سربارگذاری کنیم.

Copy Icon Program.cs
public struct Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    
    // Overloading the binary '+' operator.
    public static Point operator +(Point p1, Point p2)
    {
        int newX = p1.X + p2.X;
        int newY = p1.Y + p2.Y;
        return new Point(newX, newY);
    }

    public override string ToString() => $"({X}, {Y})";
}

در این کد، ما یک متد استاتیک تعریف کرده‌ایم که دو شیء Point را به عنوان ورودی می‌گیرد و یک شیء Point جدید که حاصل جمع مختصات آن‌هاست، برمی‌گرداند. اکنون می‌توانیم از آن به صورت زیر استفاده کنیم:

Copy Icon Program.cs
Point point1 = new(1, 2);
Point point2 = new(3, 4);

// Use the overloaded '+' operator.
Point point3 = point1 + point2;

Console.WriteLine(point3); // Output: (4, 6)

سربارگذاری عملگرهای مقایسه‌ای

شما می‌توانید عملگرهای مقایسه‌ای مانند == و != را نیز سربارگذاری کنید. این کار به شما اجازه می‌دهد تا منطق برابری سفارشی خود را تعریف کنید.

قوانین مهم:

  • عملگرهای مقایسه‌ای باید به صورت جفت سربارگذاری شوند. اگر == را سربارگذاری می‌کنید، باید != را نیز سربارگذاری کنید. همین قانون برای < و > و همچنین <= و >= نیز صادق است.
  • هنگام سربارگذاری == و !=، قویاً توصیه می‌شود که متدهای Equals و GetHashCode را نیز بازنویسی (override) کنید تا رفتار نوع شما در تمام سناریوها (مانند استفاده در دیکشنری‌ها) یکسان و قابل پیش‌بینی باشد.
Copy Icon Program.cs
// Inside the Point struct from before...

// Overloading the '==' operator.
public static bool operator ==(Point p1, Point p2)
{
    return p1.X == p2.X && p1.Y == p2.Y;
}

// Overloading the '!=' operator. It's best to define it in terms of '=='.
public static bool operator !=(Point p1, Point p2)
{
    return !(p1 == p2);
}

// Overriding Equals and GetHashCode for consistency is also required.
public override bool Equals(object obj) => obj is Point other && this == other;
public override int GetHashCode() => HashCode.Combine(X, Y);