في لغة C#، عندنا طريقتين أساسيين لمقارنة الكائنات أو القيم:
Equals
method\==
operator
الاتنين ليهم أدوار متشابهة ولكن فيه فروق مهمة جدًا بينهم، خصوصًا لما نتعامل مع الكلاس (class) و الاستراكت (struct). خليني أشرحلك بالتفصيل الفرق بين كل واحدة فيهم، وازاي بتشتغل في الحالتين.
افهم الفرق بين الـ Cs Value and Reference Types واعرف ان Class عبارة عن Reference و Struct عبارة عن Value
1. Equals
method
وصف Equals
:
- الميثود
Equals
هي method موجودة في الأساس في الكلاس Cs System.Object، واللي بيعتبر الجذر لكل الكلاسات في C#. - يعني أي كائن في C# عنده الميثود
Equals
. - الافتراضية بتاعتها في الكلاس بتقارن بين مراجع (references) الكائنات، يعني ببساطة بتسأل: “هل الكائن ده هو نفس الكائن التاني في الذاكرة؟“.
الـCs Class
- في الكلاس الافتراضي،
Equals
بتعمل مقارنة مرجعية (reference comparison). بمعنى إن لو عندك اتنين كائنات من نفس النوع، هتقارنهم وتشوف إذا كانوا بيشيروا لنفس المكان في الذاكرة.
الـCs Struct
- في الاستراكت،
Equals
بتعمل مقارنة قيمة (value comparison) افتراضيًا. لأن الاستراكت بيتم تخزينه بالقيمة، وبالتالي المقارنة هتكون على المحتوى الداخلي (القيم).
تخصيص Equals
:
ممكن تكتب نسختك الخاصة من الميثود Equals
في الكلاس أو الاستراكت، وتحدد فيها إزاي عايز الكائنات تتقارن.
غالبًا ده بيكون مفيد لو بتقارن كائنات ليها أكتر من خاصية (property) وعايز المقارنة تبقى على القيم مش على المراجع.
العملية دي مبتحصلش غير في الـ Class في الغالب عشان تخليه يقارن Values
مثال:
public class Person
{
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj is Person other)
{
return this.Name == other.Name;
}
return false;
}
}
2. \==
operator
وصف \==
:
\==
هو operator مخصص للمقارنة، ولكن سلوكه الافتراضي بيختلف بين الكلاس والاستراكت.- بشكل افتراضي، في الكلاس بيعمل مقارنة مرجعية (reference comparison)، وفي الاستراكت بيعمل مقارنة قيمية (value comparison).
في الكلاس:
- في الكلاس الافتراضي،
\==
بيقارن إذا كان الكائنين بيشيروا لنفس المكان في الذاكرة. - يعني لو عندك اتنين كائنات بنفس الخصائص، لكن محطوطين في أماكن مختلفة في الذاكرة، الـ
\==
الافتراضي هيقول إنهم مش متساويين.
في الاستراكت:
- في الاستراكت، الافتراضي إن الـ
\==
بيقارن القيمة. يعني لو عندك استراكتين بنفس القيم، هيكونوا متساويين لأن المقارنة هنا بتكون على المحتوى.
تخصيص الـ \==
:
- زي
Equals
، ممكن تعيد كتابة الـ\==
(بما يعرف بـ operator overloading) علشان تحدد إزاي الكائنات تتقارن لما تستخدم الـ\==
مع نوع معين. - بنعمل العملية دي في الغالب مع الـ Struct
مثال:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public static bool operator ==(Point p1, Point p2)
{
return p1.X == p2.X && p1.Y == p2.Y;
}
public static bool operator !=(Point p1, Point p2)
{
return !(p1 == p2);
}
}
الفروق الأساسية بين Equals
و \==
:
في الكلاس:
- الـ
Equals
الافتراضية: تقارن إذا كان الكائنين بيشيروا لنفس المرجع (reference). \==
الافتراضي: بيعمل نفس اللي بتعملهEquals
، وبيقارن المراجع (الـ References - Addresses).- بنعمل Overload لـ Equals انها تقارن الـ Values
في الاستراكت:
- الـ**
Equals
الافتراضية**: بتقارن القيم الداخلية للاستراكتات. \==
الافتراضي: بيقارن القيم زيEquals
.
متى تستخدم كل واحدة؟
- استخدم
Equals
لو بتتعامل مع كائنات (كلاسات) وعايز تخصيص عملية المقارنة بناءً على خصائص معينة جوه الكائن. - استخدم
\==
لو بتتعامل مع مقارنة مرجعية أو لو عايز تعمل operator overloading وتعيد كتابة سلوك المقارنة بنفسك.
الخلاصة:
-
في الكلاس:
- الـ
Equals
: افتراضيًا تقارن المراجع (Reference).- بنعملها Overloading عشان تقارن الـ Value
\==
: افتراضيًا تقارن المراجع (Reference).
- الـ
-
في الاستراكت:
- الـ
Equals
: افتراضيًا تقارن القيم (Value). \==
: افتراضيًا تقارن القيم (Value).
- الـ
وفي النهاية، لو عايز سلوك المقارنة يكون خاص بنوع الكائنات اللي بتتعامل معاها، الأفضل إنك تعيد كتابة الميثود Equals
وتخصصها حسب احتياجاتك.