سؤال

لقد صادفت هذا مؤخرًا، وحتى الآن كنت سعيدًا بتجاوز عامل المساواة (==) و/أو يساوي طريقة لمعرفة ما إذا كان نوعان من المراجع يحتويان بالفعل على نفس الشيء بيانات (أي.حالتان مختلفتان تبدوان متشابهتين).

لقد كنت أستخدم هذا أكثر منذ أن بدأت في إجراء المزيد من الاختبارات الآلية (مقارنة البيانات المرجعية/المتوقعة بتلك التي تم إرجاعها).

أثناء النظر في بعض إرشادات معايير الترميز في MSDN لقد صادفت شرط الذي ينصح ضده.الآن أنا أفهم لماذا المقال يقول هذا (لأنهم ليسوا متماثلين مثال) لكنه لا يجيب على السؤال:

  1. ما هي أفضل طريقة لمقارنة نوعين مرجعيين؟
  2. هل يجب أن ننفذ IComparable؟(لقد رأيت أيضًا إشارة إلى أنه يجب حجز هذا لأنواع القيمة فقط).
  3. هل هناك واجهة ما لا أعرف عنها؟
  4. هل يجب أن نلف أنفسنا فقط؟!

شكرا جزيلا ^_^

تحديث

يبدو أنني أخطأت في قراءة بعض الوثائق (لقد كان يومًا طويلًا) وتجاوزت ذلك يساوي قد يكون الطريق ..

إذا كنت تقوم بتنفيذ أنواع المرجعية ، فيجب عليك التفكير في تجاوز طريقة متساوين في نوع مرجع إذا كان نوعك يبدو وكأنه نوع أساسي مثل نقطة وسلسلة و bignumber وما إلى ذلك.يجب ألا تزيد معظم أنواع المرجع المساواة عامل ، حتى إذا تجاوزوا يساوي.ومع ذلك ، إذا كنت تقوم بتنفيذ نوع مرجعي يهدف إلى الحصول على دلالات القيمة ، مثل نوع الرقم المعقد ، فيجب عليك تجاوز مشغل المساواة.

هل كانت مفيدة؟

المحلول

يبدو أنك تقوم بالترميز في C#، والتي تحتوي على طريقة تسمى Equals والتي يجب على فصلك تنفيذها، إذا كنت تريد مقارنة كائنين باستخدام مقياس آخر غير "هل هذان المؤشران (لأن مقابض الكائنات مجرد مؤشرات) نفس عنوان الذاكرة؟".

لقد حصلت على بعض نماذج التعليمات البرمجية من هنا:

class TwoDPoint : System.Object
{
    public readonly int x, y;

    public TwoDPoint(int x, int y)  //constructor
    {
        this.x = x;
        this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        TwoDPoint p = obj as TwoDPoint;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

جافا لديها آليات مشابهة جدا.ال يساوي () الطريقة هي جزء من هدف class، وسيقوم فصلك بتحميله بشكل زائد إذا كنت تريد هذا النوع من الوظائف.

السبب الذي قد يجعل التحميل الزائد '==' فكرة سيئة للكائنات هو أنك عادةً ما تريد أن تكون قادرًا على إجراء مقارنات "هل هذا هو نفس المؤشر".يتم الاعتماد عليها عادة، على سبيل المثال، لإدراج عنصر في قائمة حيث لا يسمح بالتكرارات، وقد لا تعمل بعض عناصر إطار العمل الخاص بك إذا تم تحميل هذا العامل بشكل زائد بطريقة غير قياسية.

نصائح أخرى

تنفيذ المساواة في .NET بشكل صحيح وفعال و دون تكرار التعليمات البرمجية انه صعب.على وجه التحديد، بالنسبة للأنواع المرجعية ذات دلالات القيمة (أي: الأنواع الثابتة التي تتعامل مع التكافؤ على أنه مساواة)، يجب عليك التنفيذ ال System.IEquatable<T> واجهه المستخدم, ، ويجب عليك تنفيذ جميع العمليات المختلفة (Equals, GetHashCode و ==, !=).

على سبيل المثال، إليك فئة تطبق المساواة في القيمة:

class Point : IEquatable<Point> {
    public int X { get; }
    public int Y { get; }

    public Point(int x = 0, int y = 0) { X = x; Y = y; }

    public bool Equals(Point other) {
        if (other is null) return false;
        إرجاع X.Equals(other.X) && Y.Equals(other.Y);
    }

    public override bool Equals(object obj) => Equals(obj as Point);

    public static bool operator ==(Point lhs, Point rhs) => object.Equals(lhs, rhs);

    public static bool operator !=(Point lhs, Point rhs) => ! (lhs == rhs);

    public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();
}

الأجزاء المنقولة الوحيدة في الكود أعلاه هي الأجزاء الغامقة:السطر الثاني في Equals(Point other) و ال GetHashCode() طريقة.يجب أن يظل الرمز الآخر دون تغيير.

بالنسبة للفئات المرجعية التي لا تمثل قيمًا غير قابلة للتغيير، لا تقم بتنفيذ عوامل التشغيل == و !=.بدلاً من ذلك، استخدم معناها الافتراضي، وهو مقارنة هوية الكائن.

الرمز عمدا يساوي حتى كائنات من نوع فئة مشتقة.في كثير من الأحيان، قد لا يكون هذا مرغوبًا لأن المساواة بين الفئة الأساسية والفئات المشتقة ليست محددة بشكل جيد.لسوء الحظ، .NET وإرشادات الترميز ليست واضحة جدًا هنا.تم نشر الكود الذي أنشأه Resharper في إجابة أخرى, ، يكون عرضة للسلوك غير المرغوب فيه في مثل هذه الحالات بسبب Equals(object x) و Equals(SecurableResourcePermission x) سوف علاج هذه الحالة بشكل مختلف.

ولتغيير هذا السلوك، يجب إدخال فحص نوع إضافي في الملف المكتوب بقوة Equals الطريقة أعلاه:

public bool Equals(Point other) {
    if (other is null) return false;
    if (other.GetType() != GetType()) return false;
    إرجاع X.Equals(other.X) && Y.Equals(other.Y);
}

لقد قمت أدناه بتلخيص ما عليك القيام به عند تنفيذ IEquatable وقدمت التبرير من صفحات وثائق MSDN المختلفة.


ملخص

  • عند الرغبة في اختبار مساواة القيمة (مثل عند استخدام كائنات في مجموعات)، يجب عليك تنفيذ واجهة IEquatable وتجاوز Object.Equals وGetHashCode لفصلك الدراسي.
  • عند الرغبة في اختبار المساواة المرجعية، يجب عليك استخدام عامل التشغيل==،عامل التشغيل!= و Object.ReferenceEquals.
  • يجب عليك فقط تجاوز عامل التشغيل== وعامل التشغيل!= for أنواع القيمة وأنواع المراجع غير القابلة للتغيير.

التبرير

متساوي

يتم استخدام واجهة System.IEquatable لمقارنة مثيلين لكائن من أجل المساواة.تتم مقارنة الكائنات بناءً على المنطق المطبق في الفصل.تؤدي المقارنة إلى قيمة منطقية تشير إلى ما إذا كانت الكائنات مختلفة.وهذا على النقيض من واجهة System.IComparable، التي تُرجع عددًا صحيحًا يشير إلى كيفية اختلاف قيم الكائنات.

تعلن الواجهة IEquatable عن طريقتين يجب تجاوزهما.يحتوي أسلوب Equals على التنفيذ لإجراء المقارنة الفعلية وإرجاع صحيح إذا كانت قيم الكائنات متساوية، أو خطأ إذا لم تكن كذلك.يجب أن تقوم طريقة GetHashCode بإرجاع قيمة تجزئة فريدة يمكن استخدامها لتعريف الكائنات المتطابقة التي تحتوي على قيم مختلفة بشكل فريد.نوع خوارزمية التجزئة المستخدمة خاص بالتنفيذ.

طريقة IEquatable.Equals

  • يجب عليك تطبيق IEquatable لكائناتك للتعامل مع احتمالية تخزينها في مصفوفة أو مجموعة عامة.
  • إذا قمت بتطبيق IEquatable، فيجب عليك أيضًا تجاوز تطبيقات الفئة الأساسية لـ Object.Equals(Object) وGetHashCode بحيث يكون سلوكهم متسقًا مع سلوك أسلوب IEquatable.Equals

إرشادات لتجاوز Equals() والمشغل == (دليل برمجة C#)

  • x.Equals(x) يُرجع صحيحًا.
  • تُرجع x.Equals(y) نفس قيمة y.Equals(x)
  • إذا كانت (x.Equals(y) && y.Equals(z)) تُرجع صحيحًا، فإن x.Equals(z) تُرجع صحيحًا.
  • الدعوات المتتالية لـ x.يساوي (y) يُرجع نفس القيمة طالما لم يتم تعديل الكائنات المشار إليها بواسطة x وy.
  • س.يساوي (خالية) يُرجع خطأ (لأنواع القيم غير الخالية فقط.لمزيد من المعلومات، راجع أنواع لاغية (دليل البرمجة C#).)
  • يجب ألا يؤدي التطبيق الجديد لـ Equals إلى استثناءات.
  • من المستحسن أن تقوم أي فئة تتجاوز Equals بتجاوز Object.GetHashCode أيضًا.
  • من المستحسن أنه بالإضافة إلى تنفيذ Equals(object)، فإن أي فئة تقوم أيضًا بتطبيق Equals(type) لنوعها الخاص، لتحسين الأداء.

افتراضيًا، يقوم عامل التشغيل == باختبار المساواة المرجعية عن طريق تحديد ما إذا كان هناك مرجعان يشيران إلى نفس الكائن. لذلك، لا يتعين على أنواع المراجع تنفيذ عامل التشغيل == للحصول على هذه الوظيفة.عندما يكون النوع غير قابل للتغيير، أي أنه لا يمكن تغيير البيانات الموجودة في المثيل، فإن عامل التحميل الزائد == لمقارنة مساواة القيمة بدلاً من المساواة المرجعية يمكن أن يكون مفيدًا لأنه، ككائنات غير قابلة للتغيير، يمكن اعتبارها هي نفسها طالما حيث أن لهما نفس القيمة. ليس من الجيد تجاوز عامل التشغيل == في الأنواع غير القابلة للتغيير.

  • عامل التحميل الزائد == يجب ألا تطرح التطبيقات استثناءات.
  • أي نوع يزيد التحميل على عامل التشغيل == يجب أيضًا أن يزيد تحميل عامل التشغيل !=.

== المشغل (مرجع C#)

  • بالنسبة لأنواع القيم المحددة مسبقًا، يُرجع عامل المساواة (==) صحيحًا إذا كانت قيم معاملاته متساوية، ويعيد خطأً بخلاف ذلك.
  • بالنسبة لأنواع المراجع الأخرى غير السلسلة، == تُرجع صحيحًا إذا كان معاملاها يشيران إلى نفس الكائن.
  • بالنسبة لنوع السلسلة، == يقارن قيم السلاسل.
  • عند اختبار القيمة الخالية باستخدام مقارنات == داخل تجاوزات عامل التشغيل==، تأكد من استخدام عامل تشغيل فئة الكائن الأساسي.إذا لم تقم بذلك، سيحدث التكرار اللانهائي مما يؤدي إلى تجاوز سعة المكدس.

أسلوب Object.Equals (كائن)

إذا كانت لغة البرمجة الخاصة بك تدعم التحميل الزائد للمشغل وإذا اخترت التحميل الزائد لعامل المساواة لنوع معين، فيجب أن يتجاوز هذا النوع طريقة Equals.يجب أن تُرجع مثل هذه التطبيقات لطريقة التساوي نفس النتائج التي يُرجعها عامل المساواة

المبادئ التوجيهية التالية هي لتنفيذ أ نوع القيمة:

  • خذ بعين الاعتبار تجاوز يساوي للحصول على أداء أعلى من ذلك الذي يوفره التنفيذ الافتراضي لـ Equals على ValueType.
  • إذا قمت بتجاوز يساوي وكانت اللغة تدعم التحميل الزائد لعامل التشغيل، فيجب عليك تحميل عامل المساواة بشكل زائد لنوع القيمة الخاص بك.

المبادئ التوجيهية التالية هي لتنفيذ أ نوع مرجع:

  • فكر في تجاوز يساوي على نوع مرجعي إذا كانت دلالات النوع تعتمد على حقيقة أن النوع يمثل بعض القيمة (القيم).
  • يجب ألا تزيد معظم أنواع المراجع من التحميل الزائد على عامل المساواة، حتى إذا تجاوزت يساوي.ومع ذلك، إذا كنت تقوم بتنفيذ نوع مرجعي مخصص له دلالات قيمة، مثل نوع رقم مركب، فيجب عليك تجاوز عامل المساواة.

مسكتك إضافية

توصي هذه المقالة فقط بعدم تجاوز عامل المساواة (بالنسبة لأنواع المراجع)، وليس ضد تجاوز يساوي.يجب عليك تجاوز يساوي داخل الكائن الخاص بك (المرجع أو القيمة) إذا كانت عمليات التحقق من المساواة تعني شيئًا أكثر من مجرد عمليات التحقق من المرجع.إذا كنت تريد واجهة، يمكنك أيضًا تنفيذها متساوي (تستخدم من قبل المجموعات العامة).إذا قمت بتطبيق IEquatable، فيجب عليك أيضًا تجاوز يساوي، كما ينص قسم ملاحظات IEquatable:

إذا قمت بتطبيق IEquatable<T>، فيجب عليك أيضًا تجاوز تطبيقات الفئة الأساسية لـ Object.Equals(Object) وGetHashCode بحيث يكون سلوكهما متسقًا مع سلوك الأسلوب IEquatable<T>.Equals.إذا قمت بتجاوز Object.Equals(Object)، فسيتم أيضًا استدعاء التنفيذ الذي تم تجاوزه في استدعاءات أسلوب Equals(System.Object, System.Object) الثابت في فصلك الدراسي.وهذا يضمن أن جميع استدعاءات الأسلوب Equals تُرجع نتائج متسقة.

فيما يتعلق بما إذا كان يجب عليك تنفيذ المساواة و/أو عامل المساواة:

من تنفيذ طريقة التساوي

يجب ألا تزيد معظم أنواع المراجع من التحميل الزائد على عامل المساواة، حتى لو تجاوزت يساوي.

من المبادئ التوجيهية لتنفيذ المساواة وعامل المساواة (==)

قم بتجاوز أسلوب Equals عندما تقوم بتطبيق عامل المساواة (==)، واجعلهم يفعلون نفس الشيء.

يشير هذا فقط إلى أنك تحتاج إلى تجاوز يساوي كلما قمت بتنفيذ عامل المساواة.نعم هو كذلك لا لنفترض أنك بحاجة إلى تجاوز عامل المساواة عند تجاوز يساوي.

بالنسبة للكائنات المعقدة التي ستؤدي إلى مقارنات محددة، فإن تطبيق IComparable وتحديد المقارنة في طرق المقارنة يعد تطبيقًا جيدًا.

على سبيل المثال، لدينا كائنات "مركبة" حيث قد يكون الاختلاف الوحيد هو رقم التسجيل ونستخدمه للمقارنة للتأكد من أن القيمة المتوقعة التي يتم إرجاعها في الاختبار هي القيمة التي نريدها.

أميل إلى استخدام ما يصنعه Resharper تلقائيًا.على سبيل المثال، قام بإنشاء هذا تلقائيًا لأحد أنواع المراجع الخاصة بي:

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    return obj.GetType() == typeof(SecurableResourcePermission) && Equals((SecurableResourcePermission)obj);
}

public bool Equals(SecurableResourcePermission obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    return obj.ResourceUid == ResourceUid && Equals(obj.ActionCode, ActionCode) && Equals(obj.AllowDeny, AllowDeny);
}

public override int GetHashCode()
{
    unchecked
    {
        int result = (int)ResourceUid;
        result = (result * 397) ^ (ActionCode != null ? ActionCode.GetHashCode() : 0);
        result = (result * 397) ^ AllowDeny.GetHashCode();
        return result;
    }
}

إذا كنت تريد تجاوز == وما زلت تفعل الشيكات المرجعية، لا يزال بإمكانك استخدامها Object.ReferenceEquals.

يبدو أن Microsoft قد غيرت أسلوبها، أو على الأقل هناك معلومات متضاربة حول عدم التحميل الزائد على عامل المساواة.وفقا لهذا مقالة مايكروسوفت بعنوان كيف:تحديد مساواة القيمة للنوع:

"يمكن استخدام عوامل التشغيل == و!= مع الفئات حتى لو لم تقم الفئة بتحميلها بشكل زائد.ومع ذلك، السلوك الافتراضي هو إجراء فحص المساواة المرجعية.في الفصل الدراسي، إذا قمت بتحميل الأسلوب Equals بشكل زائد، فيجب عليك التحميل الزائد على عوامل التشغيل == و!=، لكن ذلك غير مطلوب."

بحسب إريك ليبرت في كتابه إجابة لسؤال سألت عنه الحد الأدنى من رمز المساواة في C# - هو يقول:

"الخطر الذي تواجهه هنا هو أنك تحصل على عامل التشغيل == المحدد لك والذي يشير إلى المساواة افتراضيًا.يمكن أن ينتهي بك الأمر بسهولة في موقف حيث تقوم طريقة Equals المثقلة بتقدير المساواة و== تشير إلى المساواة، ثم تستخدم عن طريق الخطأ المساواة المرجعية في الأشياء غير المتساوية ذات القيمة المتساوية.هذه ممارسة معرضة للخطأ ويصعب اكتشافها من خلال مراجعة التعليمات البرمجية البشرية.

منذ عامين، عملت على خوارزمية تحليل ثابتة للكشف عن هذا الموقف إحصائيًا، ووجدنا معدل خلل يبلغ حوالي حالتين لكل مليون سطر من التعليمات البرمجية عبر جميع قواعد التعليمات البرمجية التي درسناها.عند النظر فقط في قواعد التعليمات البرمجية التي تجاوزت مبدأ Equals في مكان ما، كان من الواضح أن معدل الخلل أعلى بكثير!

علاوة على ذلك، ضع في اعتبارك التكاليف مقابل المخاطر.إذا كان لديك بالفعل تطبيقات IComparable، فإن كتابة جميع العوامل ستكون عبارة عن سطور بسيطة لن تحتوي على أخطاء ولن يتم تغييرها أبدًا.إنه أرخص رمز ستكتبه على الإطلاق.إذا أُعطيت الاختيار بين التكلفة الثابتة للكتابة واختبار عشرات الطرق الصغيرة مقابل التكلفة غير المحدودة للعثور على خطأ يصعب رؤيته وإصلاحه حيث يتم استخدام المساواة المرجعية بدلاً من المساواة في القيمة، فأنا أعرف أيهما سأختار."

لن يستخدم .NET Framework مطلقًا == أو != مع أي نوع تكتبه.لكن الخطر هو ما سيحدث إذا فعل شخص آخر ذلك.لذا، إذا كان الفصل مخصصًا لطرف ثالث، فسأقدم دائمًا عاملي التشغيل == و!=.إذا كان المقصود من الفصل أن يتم استخدامه داخليًا من قبل المجموعة فقط، فمن المحتمل أن أقوم بتطبيق عاملي التشغيل == و!=.

سأقوم فقط بتنفيذ عوامل التشغيل <، <=، >، >= إذا تم تنفيذ IComparable.يجب تنفيذ IComparable فقط إذا كان النوع يحتاج إلى دعم الطلب - كما هو الحال عند الفرز أو استخدامه في حاوية عامة مرتبة مثل SortedSet.

إذا كان لدى المجموعة أو الشركة سياسة مطبقة لعدم تنفيذ عاملي التشغيل == و!= - فسوف أتبع هذه السياسة بالطبع.إذا كانت مثل هذه السياسة موجودة، فسيكون من الحكمة تطبيقها باستخدام أداة تحليل كود الأسئلة والأجوبة التي تشير إلى أي تواجد لعاملي التشغيل == و!= عند استخدامها مع نوع مرجعي.

أعتقد أن الحصول على شيء بسيط مثل فحص الكائنات للتأكد من صحتها أمر صعب بعض الشيء مع تصميم .NET.

للهيكل

1) التنفيذ IEquatable<T>.يعمل على تحسين الأداء بشكل ملحوظ.

2) بما أن لديك ملكك الخاص Equals الآن، تجاوز GetHashCode, ، وأن تكون متسقة مع تجاوزات التحقق من المساواة المختلفة object.Equals أيضًا.

3) الحمولة الزائدة == و != لا يلزم تنفيذ العوامل دينيًا نظرًا لأن المترجم سوف يحذرك إذا قمت عن غير قصد بمساواة بنية بأخرى بـ == أو !=, ولكن من الجيد أن تفعل ذلك لتكون متسقًا مع Equals طُرق.

public struct Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is Entity))
            return false;

        return Equals((Entity)obj);
    }

    public static bool operator ==(Entity e1, Entity e2)
    {
        return e1.Equals(e2);
    }

    public static bool operator !=(Entity e1, Entity e2)
    {
        return !(e1 == e2);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

للصف

من مرض التصلب العصبي المتعدد:

يجب ألا تزيد معظم أنواع المراجع من التحميل الزائد على عامل المساواة، حتى لو تجاوزت يساوي.

إلي == يبدو وكأنه قيمة المساواة، أشبه بالسكر النحوي ل Equals طريقة.كتابة a == b هو أكثر سهولة من الكتابة a.Equals(b).نادرًا ما نحتاج إلى التحقق من المساواة المرجعية.في المستويات المجردة التي تتعامل مع التمثيلات المنطقية للأشياء المادية، هذا ليس شيئًا نحتاج إلى التحقق منه.أعتقد أن وجود دلالات مختلفة ل == و Equals يمكن أن يكون مربكًا في الواقع.وأعتقد أنه كان ينبغي أن يكون == من أجل المساواة في القيمة و Equals كمرجع (أو اسم أفضل مثل IsSameAs) المساواة في المقام الأول. أود ألا آخذ إرشادات مرض التصلب العصبي المتعدد على محمل الجد هنا، ليس فقط لأنها ليست طبيعية بالنسبة لي، ولكن أيضًا بسبب التحميل الزائد == لا يسبب أي ضرر كبير. هذا على عكس عدم تجاوز غير عام Equals أو GetHashCode والتي يمكن أن تعض، لأن الإطار لا يستخدم == في أي مكان ولكن فقط إذا استخدمناه بأنفسنا.الفائدة الحقيقية الوحيدة التي أستفيد منها لا الزائد == و != سيكون الاتساق مع تصميم الإطار بأكمله الذي ليس لدي أي سيطرة عليه.وهذا بالفعل شيء كبير، للأسف سألتزم به.

مع دلالات مرجعية (كائنات قابلة للتغيير)

1) تجاوز Equals و GetHashCode.

2) التنفيذ IEquatable<T> ليس أمرًا ضروريًا، ولكنه سيكون لطيفًا إذا كان لديك واحدة.

public class Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        //if your below implementation will involve objects of derived classes, then do a 
        //GetType == other.GetType comparison
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Entity);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

مع دلالات القيمة (الكائنات غير القابلة للتغيير)

هذا هو الجزء الصعب.يمكن أن تفسد بسهولة إذا لم يتم الاعتناء بها..

1) تجاوز Equals و GetHashCode.

2) الزائد == و != كثيرا Equals. تأكد من أنه يعمل مع القيم الخالية.

2) التنفيذ IEquatable<T> ليس أمرًا ضروريًا، ولكنه سيكون لطيفًا إذا كان لديك واحدة.

public class Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        //if your below implementation will involve objects of derived classes, then do a 
        //GetType == other.GetType comparison
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Entity);
    }

    public static bool operator ==(Entity e1, Entity e2)
    {
        if (ReferenceEquals(e1, null))
            return ReferenceEquals(e2, null);

        return e1.Equals(e2);
    }

    public static bool operator !=(Entity e1, Entity e2)
    {
        return !(e1 == e2);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

انتبه بشكل خاص لترى كيف ينبغي أن يكون الأمر إذا كان من الممكن توريث فئتك، في مثل هذه الحالات، سيتعين عليك تحديد ما إذا كان كائن الفئة الأساسية يمكن أن يكون مساويًا لكائن فئة مشتقة.من الناحية المثالية، إذا لم يتم استخدام أي كائنات من فئة مشتقة للتحقق من المساواة، فيمكن أن يكون مثيل الفئة الأساسية مساويًا لمثيل فئة مشتقة وفي مثل هذه الحالات، ليست هناك حاجة للتحقق Type المساواة بشكل عام Equals من الطبقة الأساسية.

بشكل عام، احرص على عدم تكرار التعليمات البرمجية.كان بإمكاني إنشاء فئة أساسية مجردة عامة (IEqualizable<T> أو نحو ذلك) كقالب للسماح بإعادة الاستخدام بشكل أسهل، ولكن للأسف في C# يمنعني ذلك من الاشتقاق من فئات إضافية.

جميع الإجابات المذكورة أعلاه لا تأخذ في الاعتبار تعدد الأشكال، وغالبًا ما تريد أن تستخدم المراجع المشتقة المعادلات المشتقة حتى عند مقارنتها عبر مرجع أساسي.يرجى الاطلاع على السؤال / المناقشة / الإجابات هنا - المساواة وتعدد الأشكال

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top