تنفيذ IEquatable
وفّروا مساواة آمنة للنوع باستخدام Equals
تنفيذ IEquatable درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.
لماذا IEquatable<T>؟
توفر IEquatable<T> أسلوبًا Equals(T other) محدد النوع بقوة. فهو يتجنب التغليف للأنواع القيمية والتحويلات للأنواع المرجعية، مما يجعل المساواة أسرع وأوضح.
تنفيذ الواجهة
نفّذ IEquatable<T> ووفّر Equals(T other). وينبغي لك أيضًا إعادة تعريف object.Equals الموروث وGetHashCode للحفاظ على اتساق جميع المسارات.
using System;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Point(1, 2).Equals(new Point(1, 2)));
}
}تجنب التغليف للهياكل
يؤدي object.Equals(object) غير العام إلى تغليف وسيطة من نوع هيكل. أما Equals(Point other) المحدد النوع من IEquatable<T> فيستقبل الهيكل مباشرةً، ولذلك لا يحدث أي تخصيص.
using System;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y; // no boxing
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
Point a = new Point(3, 4);
Point b = new Point(3, 4);
Console.WriteLine(a.Equals(b)); // calls the typed overload
}
}تستخدم المجموعات IEquatable<T>
تفضّل List<T>.Contains وDictionary وHashSet استخدام IEquatable<T>.Equals عند توفره. ويجعل تنفيذه هذه العمليات فعالة وصحيحة لنوعك.
using System;
using System.Collections.Generic;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
var list = new List<Point> { new Point(0, 0), new Point(1, 1) };
Console.WriteLine(list.Contains(new Point(1, 1)));
}
}الأنواع المرجعية وIEquatable<T>
يمكن للفئات أيضًا تنفيذ IEquatable<T>. إذ يتجنب Equals المحدد النوع إجراء تحويل، وتتعامل صراحةً مع null للوسيطة المرجعية.
using System;
public class Person : IEquatable<Person>
{
public string Name;
public Person(string name) { Name = name; }
public bool Equals(Person other) => other != null && other.Name == Name;
public override bool Equals(object obj) => Equals(obj as Person);
public override int GetHashCode() => Name?.GetHashCode() ?? 0;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Person("Ada").Equals(new Person("Ada")));
Console.WriteLine(new Person("Ada").Equals((Person)null));
}
}توجيه object.Equals عبر الأسلوب المحدد النوع
من الأنماط النظيفة كتابة المقارنة مرة واحدة في Equals(T) وجعل object.Equals يفوض إليها. ويضمن ذلك تطابق سلوك الاثنين.
using System;
public struct Id : IEquatable<Id>
{
public int Value;
public Id(int value) { Value = value; }
public bool Equals(Id other) => Value == other.Value;
public override bool Equals(object obj) => obj is Id other && Equals(other);
public override int GetHashCode() => Value;
}
public class Program
{
public static void Main()
{
object boxed = new Id(5);
Console.WriteLine(boxed.Equals(new Id(5)));
}
}مقارنة حقول متعددة
بالنسبة إلى الأنواع التي تحتوي على عدة حقول، قارنها جميعًا في Equals. ولا تكون مثيلتان متساويتين إلا إذا تطابقت كل الحقول ذات الصلة.
using System;
public struct DateRange : IEquatable<DateRange>
{
public int Start, End;
public DateRange(int start, int end) { Start = start; End = end; }
public bool Equals(DateRange other) => Start == other.Start && End == other.End;
public override bool Equals(object obj) => obj is DateRange d && Equals(d);
public override int GetHashCode() => HashCode.Combine(Start, End);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new DateRange(1, 5).Equals(new DateRange(1, 5)));
Console.WriteLine(new DateRange(1, 5).Equals(new DateRange(1, 6)));
}
}الاقتران مع المؤثرات
اجمع بين IEquatable<T> و== و!= حتى يتمكن المستخدمون من المقارنة بأي من الصيغتين، مع اعتماد كلتيهما على المقارنة المحددة النوع نفسها.
using System;
public struct Money : IEquatable<Money>
{
public decimal Amount;
public Money(decimal a) { Amount = a; }
public bool Equals(Money other) => Amount == other.Amount;
public override bool Equals(object obj) => obj is Money m && Equals(m);
public override int GetHashCode() => Amount.GetHashCode();
public static bool operator ==(Money a, Money b) => a.Equals(b);
public static bool operator !=(Money a, Money b) => !a.Equals(b);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Money(9.99m) == new Money(9.99m));
}
}تنفذ السجلات ذلك تلقائيًا
ينشئ record في C# تلقائيًا IEquatable<T> وEquals القائمة على القيمة وGetHashCode. وعندما تكون المساواة بالقيمة هي كل ما تحتاج إليه، توفر السجلات الكثير من الشيفرة النمطية.
using System;
public record Point(int X, int Y);
public class Program
{
public static void Main()
{
var a = new Point(1, 2);
var b = new Point(1, 2);
Console.WriteLine(a.Equals(b));
Console.WriteLine(a == b);
}
}متى تنفذه يدويًا
نفّذ IEquatable<T> يدويًا عندما تحتاج إلى قواعد مخصصة للمساواة، مثل الأسماء غير الحساسة لحالة الأحرف أو تجاهل حقول معينة، وهي أمور لا يستطيع السجل التعبير عنها مباشرةً.
using System;
public class CaseInsensitiveTag : IEquatable<CaseInsensitiveTag>
{
public string Name;
public CaseInsensitiveTag(string name) { Name = name; }
public bool Equals(CaseInsensitiveTag other)
=> other != null && string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase);
public override bool Equals(object obj) => Equals(obj as CaseInsensitiveTag);
public override int GetHashCode() => Name?.ToLowerInvariant().GetHashCode() ?? 0;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new CaseInsensitiveTag("Red").Equals(new CaseInsensitiveTag("RED")));
}
}جرّب بنفسك
نفّذ IEquatable<T> لنوع مرجعي صغير، ووجّه كل مسارات المساواة عبر الأسلوب المحدد النوع.
using System;
using System.Collections.Generic;
public class Coordinate : IEquatable<Coordinate>
{
public int Lat, Lng;
public Coordinate(int lat, int lng) { Lat = lat; Lng = lng; }
public bool Equals(Coordinate other) => other != null && other.Lat == Lat && other.Lng == Lng;
public override bool Equals(object obj) => Equals(obj as Coordinate);
public override int GetHashCode() => HashCode.Combine(Lat, Lng);
}
public class Program
{
public static void Main()
{
var set = new HashSet<Coordinate> { new Coordinate(10, 20) };
Console.WriteLine(set.Contains(new Coordinate(10, 20)));
}
}اختبار سريع
تذكّر فائدة IEquatable
مراجعة
توفر IEquatable<T> مساواة آمنة من ناحية النوع.
- توفر
Equals(T other)، مما يتجنب التغليف للهياكل والتحويلات للفئات. - تفضّلها المجموعات لإجراء عمليات بحث صحيحة وفعالة.
- وجّه
object.Equalsوالمؤثرات عبر الأسلوب المحدد النوع. - تنفذها السجلات تلقائيًا؛ ونفّذها يدويًا عند الحاجة إلى قواعد مخصصة.
الأسئلة الشائعة
هل درس «تنفيذ IEquatable» مجاني؟
نعم — نص درس «تنفيذ IEquatable» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «تنفيذ IEquatable»؟
وفّروا مساواة آمنة للنوع باستخدام Equals تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «تنفيذ IEquatable»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تنفيذ IEquatable
- تجاوز GetHashCode
- تنفيذ IComparable
- IComparer للفرز المخصّص