كيف يمكنك تنفيذ GetHashCode على هيكل مع اثنين من السلسلة ، عند كل سلاسل قابلة للتبادل

StackOverflow https://stackoverflow.com/questions/70303

  •  09-06-2019
  •  | 
  •  

سؤال

لدي هيكل في C#:

public struct UserInfo
{
   public string str1
   {
     get;
     set;
   }

   public string str2
   {
     get;
     set;
   }   
}

القاعدة الوحيدة هي أن UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))

كيفية تجاوز GetHashCode وظيفة هذا الهيكل ؟

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

المحلول

MSDN:

وظيفة تجزئة يجب أن تتوفر الخصائص التالية:

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

مع الأخذ في الاعتبار الطريقة الصحيحة هي:

return str1.GetHashCode() ^ str2.GetHashCode() 

^ يمكن أن تكون بديلا مع تبادلي العملية

نصائح أخرى

انظر جون السكيت الجواب - العمليات الثنائية مثل ^ ليست جيدة ، فإنها غالبا ما تولد الاصطدام تجزئة!

public override int GetHashCode()
{
    unchecked
    {
        return (str1 ?? String.Empty).GetHashCode() +
            (str2 ?? String.Empty).GetHashCode();
    }
}

باستخدام '+' المشغل قد يكون أفضل من استخدام ' ^ ' ، لأنه على الرغم من أنك صراحة تريد ('AA', 'BB') و ('BB', 'AA') صراحة يكون نفسه ، قد لا تريد ('AA', 'AA') و ('BB', 'BB') نفسه (أو كلها على قدم المساواة أزواج في هذا الشأن).

فإن 'في أسرع وقت ممكن' القاعدة ليست كلها الالتزام بها في هذا الحل لأنه في حالة بالقيم الخالية هذا ينفذ 'GetHashCode()' على سلسلة فارغة بدلا من العودة فورا ثابت معروف ، ولكن حتى من دون صراحة قياس وأنا على استعداد أن أخمن أن الفرق لن يكون كبيرا بما يكفي للقلق إلا إذا كنت تتوقع الكثير من القيم الخالية.

  1. كقاعدة عامة, طريقة بسيطة لتوليد hashcode لفئة هو XOR جميع حقول البيانات التي يمكن أن تشارك في توليد رمز التجزئة (مع الحرص على التحقق فارغة كما أشار من قبل الآخرين).هذا أيضا يلتقي (اصطناعية؟) شرط أن hashcodes على المعلومات حول المستخدم("AA", "ب") و UserInfo("BB" ، "AA") هي نفسها.

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

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

بسيطة العامة طريقة للقيام بذلك:

return string.Format("{0}/{1}", str1, str2).GetHashCode();

إلا إذا كان لديك صارمة متطلبات الأداء, هذا هو أسهل أستطيع أن أفكر وأنا كثيرا ما استخدم هذا الأسلوب عندما أحتاج مفتاح مركب.فإنه يعالج null الحالات على ما يرام و لن يسبب (م)أي اصطدام التجزئة (في العام).إذا كنت تتوقع '/' في سلاسل الخاص بك, فقط اختر آخر فاصل لا تتوقع.

public override int GetHashCode()   
{       
    unchecked      
    {           
        return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0);       
    }   
}

الذهاب على طول خطوط ReSharper يقترح:

public int GetHashCode()
{
    unchecked
    {
        int hashCode;

        // String properties
        hashCode = (hashCode * 397) ^ (str1!= null ? str1.GetHashCode() : 0);
        hashCode = (hashCode * 397) ^ (str2!= null ? str1.GetHashCode() : 0);

        // int properties
        hashCode = (hashCode * 397) ^ intProperty;
        return hashCode;
    }
}

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

آه نعم ، كما غاري Shutler أشار إلى:

return str1.GetHashCode() + str2.GetHashCode();

يمكن تجاوز.قد تتمكن من محاولة الصب دام ارتيم المقترحة ، أو هل يمكن أن تحيط البيان في لحالها الكلمة:

return unchecked(str1.GetHashCode() + str2.GetHashCode());

محاولة الخروج من هذا واحد:

(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()

الكثير من الاحتمالات.E. g.

return str1.GetHashCode() ^ str1.GetHashCode()

ربما شيء مثل str1.GetHashCode() + str2.GetHashCode()?أو (str1.GetHashCode() + str2.GetHashCode()) / 2?بهذه الطريقة سيكون من نفسه بغض النظر عما إذا str1 و str2 هي تبديل....

نوع لهم ، ثم سلسلة لهم:

return ((str1.CompareTo(str2) < 1) ? str1 + str2 : str2 + str1)
    .GetHashCode();

GetHashCode نتيجة المفترض أن يكون:

  1. في أسرع وقت ممكن.
  2. فريدة من نوعها ممكن.

تحمل هذه في الاعتبار ، كنت أذهب مع شيء من هذا القبيل:

if (str1 == null)
    if (str2 == null)
        return 0;
    else
       return str2.GetHashCode();
else
    if (str2 == null)
        return str1.GetHashCode();
    else
       return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();

تحرير: نسيت بالقيم الخالية.رمز ثابت.

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

if (null != str1) {
    return str1.GetHashCode();
}
if (null != str2) {
    return str2.GetHashCode();
}
//Not sure what you would put here, some constant value will do
return 0;

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

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