سؤال

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

أنا في المقام الأول تجاوز Equals لسهولة اختبار وحدة بلدي رمز التسلسل الذي أفترض التسلسلية و تسلسل (XML في حالتي) يقتل إشارة المساواة لذلك أريد أن تأكد من أنها على الأقل الصحيح من قيمة المساواة.هذه الممارسة السيئة لتجاوز Equals في هذه الحالة ؟ الأساس في معظم تنفيذ التعليمات البرمجية أريد الإشارة المساواة و أنا دائما استخدام == و أنا لا تجاوز ذلك.يجب أن مجرد خلق طريقة جديدة ValueEquals أو شيء بدلا من تجاوز Equals?اعتدت أن نفترض أن الإطار يستخدم دائما == و لا Equals لمقارنة الأشياء حتى ظننت أنه كان آمنا لتجاوز Equals منذ بدا لي وكان الغرض إذا كنت تريد أن يكون لها 2 تعريف المساواة التي تختلف عن == المشغل.من قراءة العديد من الأسئلة الأخرى على الرغم من أنه يبدو أن الأمر ليس كذلك.

تحرير:

يبدو نواياي واضحة, ما أعنيه هو أن 99% من الوقت أريد القديم عادي إشارة المساواة السلوك الافتراضي, لا مفاجآت.بالنسبة حالات نادرة جدا أريد أن يكون قيمة المساواة ، وأريد أن تطلب صراحة قيمة المساواة باستخدام .Equals بدلا من ==.

عندما أفعل هذا المترجم توصي تجاوز GetHashCode وكذلك, وكيف أن هذا السؤال جاء.يبدو أن هناك تناقض أهداف GetHashCode عند تطبيقها على كائنات قابلة للتغيير ، وتلك التي يجري:

  1. إذا a.Equals(b) ثم a.GetHashCode() يجب أن == b.GetHashCode().
  2. قيمة a.GetHashCode() يجب أن لا تتغير أبدا عن عمر a.

ويبدو أن هذه بطبيعة الحال يتعارض عندما قابلة للتغيير كائن ، لأنه إذا كانت الدولة الكائن التغييرات ، نتوقع قيمة .Equals() إلى تغيير ، مما يعني أن GetHashCode يجب تغيير لتتناسب مع التغيير في .Equals(), ولكن GetHashCode يجب أن لا تغيير.

لماذا يبدو أن هناك هذا التناقض ؟ هذه التوصيات لا تنطبق على قابلة للتغيير الكائنات ؟ ربما يفترض ، ولكن قد يكون من الجدير بالذكر أنا في اشارة الى فئات لا البنيات.

القرار:

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

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

المحلول

كما أن الحقول أنه على أساس هي قابلة للتغيير?

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

أيضا ماذا لو كنت لا تريد قاموس البحث وما إلى ذلك بناء على إشارة المساواة لا تجاوز يساوي ؟

طالما أنك تنفيذ واجهة مثل IEquatable<T> هذا لا ينبغي أن يكون مشكلة.معظم تطبيقات القاموس اختيار المساواة comparer في الطريقة التي سوف تستخدم IEquatable<T> على كائن.ReferenceEquals.حتى من دون IEquatable<T>, معظم الافتراضي إلى استدعاء كائن.يساوي() والتي سوف ثم انتقل إلى التطبيق الخاص بك.

الأساس في معظم تنفيذ التعليمات البرمجية أريد الإشارة المساواة و أنا دائما استخدام == و أنا لا تجاوز ذلك.

إذا كنت تتوقع الأشياء الخاصة بك تتصرف مع قيمة المساواة يجب أن تتجاوز == و != لفرض قيمة المساواة بين جميع المقارنات.يمكن للمستخدمين الاستمرار في استخدام كائن.ReferenceEquals إذا كانت فعلا تريد الإشارة المساواة.

اعتدت أن نفترض أن الإطار يستخدم دائما == لا يساوي لمقارنة الأشياء

ما BCL يستخدم قد تغيرت قليلا مع مرور الوقت.الآن معظم الحالات التي تستخدم المساواة سوف تتخذ IEqualityComparer<T> سبيل المثال واستخدامها من أجل المساواة.في الحالات حيث لم يتم تحديد أنها سوف تستخدم EqualityComparer<T>.Default العثور على واحد.في أسوأ الأحوال هذا سوف الافتراضي إلى استدعاء كائن.يساوي

نصائح أخرى

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

إذا كنت تريد البحث عدم استخدام GetHashCode أو Equals طريقة الطبقة ، يمكنك دائما تقديم الخاص بك IEqualityComparer تنفيذ استخدام بدلا من ذلك عند إنشاء Dictionary.

على Equals الأسلوب المقصود قيمة المساواة ، لذلك ليس من الخطأ أن تنفيذ هذا الطريق.

نجاح باهر, هذا هو في الواقع عدة أسئلة في واحد :-).لذا واحدا بعد الآخر:

لقد تم ذكر أن قيمة الوقت يجب أن لا تتغير على مدى عمر من وجوه.كما أن الحقول أنه على أساس هي قابلة للتغيير?

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

الاستشهاد مستندات من جاوة خريطة واجهة:

ملاحظة:يجب توخي الحذر الشديد إذا كائنات قابلة للتغيير تستخدم خريطة مفاتيح.سلوك الخريطة لم يتم تحديد إذا كانت قيمة كائن هو تغيير في الطريقة التي يؤثر يساوي مقارنات بينما الكائن هو مفتاح الخريطة.

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

لذلك النصيحة الحقيقية هي:فقط استخدام غير قابل للتغيير الأشياء مثل المفاتيح ، والتأكد من hashcode لا يتغير أبدا إما (التي عادة ما تكون التلقائي إذا كان الكائن هو غير قابل للتغيير).

أيضا ماذا لو كنت لا تريد قاموس البحث وما إلى ذلك بناء على إشارة المساواة لا تجاوز يساوي ؟

حسنا, ابحث عن قاموس التنفيذ أن يعمل مثل هذا.ولكن المعيار مكتبة القواميس استخدام hashcode&يساوي ، وليس هناك طريقة لتغيير ذلك.

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

لا, لا أجد مقبول تماما.ومع ذلك ، يجب عدم استخدام كائنات مثل المفاتيح في القاموس/hashtable ، كما أنهم قابلة للتغيير.انظر أعلاه.

الكامنة الموضوع هنا هو كيفية تحديد فريد الكائنات.تذكر التسلسل/إلغاء التسلسل وهو أمر مهم لأن التكامل المرجعي فقدت في هذه العملية.

الجواب القصير هو أن الأشياء التي يجب تحديدها بشكل فريد من أصغر مجموعة ثابتة من المجالات التي يمكن استخدامها للقيام بذلك.هذه هي المجالات التي يجب استخدامها عند overrideing GetHashCode و يساوي.

لاختبار انه من المعقول تماما أن تحدد أيا كان تأكيدات تحتاج عادة فهي لا تعرف على نوع نفسها بل فائدة الأساليب في اختبار جناح.ربما TestSuite.AssertEquals(MyClass, MyClass) ?

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

أنا لا أعرف عن C#, كونه قريب مستجد ولكن في جاوة ، إذا تجاوز يساوي() تحتاج أيضا إلى تجاوز hashCode() للحفاظ على العقد بينهما (والعكس بالعكس)...و جافا أيضا لديه نفس قبض 22;أساسا يجبرك استخدام غير قابل للتغيير الحقول...ولكن هذه المسألة فقط على الطبقات التي تستخدم تجزئة-مفتاح جافا تطبيقات بديلة عن كل تجزئة على أساس مجموعات...التي ربما ليست سريعة ولكنها effecitely تسمح لك باستخدام قابلة للتغيير كائن رئيسي...انها مجرد (عادة) عبس بأنه "سوء التصميم".

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

لقد عملت على لغة فورتران الذي هو أكبر مني (أنا 36) الذي يكسر عندما يكون اسم المستخدم هو تغيير (مثل عندما تزوجت الفتاة ، أو مطلق ;-) ...وهكذا هي الهندسة المعتمدة الحل:على GetHashCode "طريقة" يتذكر محسوبة سابقا hashCode, يعيد حساب على hashCode (أيالظاهري isDirty علامة) وإذا حقول المفتاح تغيرت ترجع فارغة.هذا يتسبب في ذاكرة التخزين المؤقت إلى حذف "القذرة" المستخدم (عن طريق استدعاء آخر GetPreviousHashCode) ثم ذاكرة التخزين المؤقت إرجاع null, مما تسبب المستخدم إلى إعادة قراءة من قاعدة البيانات.مثيرة للاهتمام وجديرة بالاهتمام الإختراق ؛ حتى لو كنت لا أقول ذلك لنفسي ;-)

سوف المفاضلة التحولية (فقط مرغوب فيه في الحالات الزاوية) س(1) الوصول (من المرغوب فيه في جميع الحالات).مرحبا بكم في الهندسة ؛ أرض أبلغ حل وسط.

الهتافات.كيث.

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