සමානාත්මතා ක්‍රමය ඉක්මවා ගිය විට GetHashCode අභිබවා යාම වැදගත් වන්නේ ඇයි?


1458

පහත පන්තිය ලබා දී ඇත

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null) 
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

S වගුව සඳහා පේළියක් නිරූපණය කරන Equalsනිසා මම ක්‍රමය ඉක්මවා ඇත . අභිබවා යාමට වඩාත් කැමති ක්‍රමය කුමක්ද?FooFooGetHashCode

අභිබවා යාම වැදගත් වන්නේ GetHashCodeඇයි?


37
Isions ට්ටන හේතුවෙන්, විශේෂයෙන් ශබ්දකෝෂ භාවිතා කරන අතරතුර, සමාන හා ගෙටාෂ්කෝඩ් යන දෙකම ක්‍රියාත්මක කිරීම වැදගත් වේ. වස්තු දෙකක් එකම හැෂ් කේතයක් ලබා දෙන්නේ නම්, ඒවා දම්වැලෙන් ශබ්ද කෝෂයට ඇතුළත් කරනු ලැබේ. අයිතමයට ප්‍රවේශවීමේදී සමාන ක්‍රමයක් භාවිතා කරයි.
ඩාර්ත්වඩර්

Answers:


1333

ඔව්, ඔබේ අයිතමය ශබ්දකෝෂයක යතුරක් ලෙස භාවිතා කරන්නේද යන්න වැදගත් වේ, හෝ HashSet<T>, යනාදිය - මෙය (සිරිතක් නොමැති විට IEqualityComparer<T>) අයිතම බාල්දි වලට කාණ්ඩ කිරීමට භාවිතා කරන බැවින් . අයිතම දෙකක් සඳහා හැෂ් කේතය නොගැලපේ නම්, ඒවා කිසි විටෙකත් සමාන යැයි නොසැලකේ ( සමානාත්මතාවය කිසි විටෙකත් නොකියනු ඇත).

මෙම GetHashCode () ක්රමය පිළිබිඹු විය යුතුය Equalsතර්ක; නීති:

  • කාරණා දෙකක් සමාන නම් ( Equals(...) == true) එවිට ඒවා සඳහා එකම අගය ලබා දිය යුතුයGetHashCode()
  • GetHashCode()සමාන නම්, ඔවුන් එක හා සමාන වීම අවශ්‍ය නොවේ ; මෙය ision ට්ටනයක් වන අතර Equalsඑය සැබෑ සමානාත්මතාවයක් දැයි බැලීමට කැඳවනු ලැබේ.

මෙම අවස්ථාවේ දී, " return FooId;" සුදුසු GetHashCode()ක්රියාත්මක කිරීමක් ලෙස පෙනේ. ඔබ බහු ගුණාංග පරික්ෂා කරන්නේ නම්, විකර්ණ isions ට්ටන අඩු කිරීම සඳහා පහත දැක්වෙන කේතය භාවිතා කර ඒවා ඒකාබද්ධ කිරීම සාමාන්‍ය දෙයකි (එනම් new Foo(3,5)වෙනස් හැෂ් කේතයක් ඇති බැවින් new Foo(5,3)):

unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
    int hash = 13;
    hash = (hash * 7) + field1.GetHashCode();
    hash = (hash * 7) + field2.GetHashCode();
    ...
    return hash;
}

අපොයි - පහසුව සඳහා, ඔබ ද ලබා සලකා බැලීමට ඉඩ ==හා !=ආධිපත්යධාරී විට ක්රියාකරුවන් Equalsහා GetHashCode.


ඔබ මෙම වැරැද්ද කළ විට කුමක් සිදුවේද යන්න නිරූපණය කිරීම මෙහි ඇත.


51
මට අහන්න පුළුවන්ද ඔබ එවැනි සාධක සමඟ ගුණ කරනවාද?
ලියාන්ඩ්‍රෝ ලෝපෙස්

22
ඇත්තටම, මට ඔවුන්ගෙන් එක් කෙනෙක් නැති වෙන්න පුළුවන්. කාරණය වන්නේ isions ට්ටන ගණන අවම කිරීමට උත්සාහ කිරීමයි - එවිට object 1,0,0 a වස්තුවකට has 0,1,0} සහ {0,0,1 to ට වෙනස් හැෂ් එකක් ඇත (මා අදහස් කරන දේ ඔබ දුටුවහොත් ),
මාක් ග්‍රෙවෙල්

13
එය වඩාත් පැහැදිලි කිරීම සඳහා මම සංඛ්‍යා වෙනස් කළෙමි (සහ බීජයක් එකතු කළෙමි). සමහර කේත විවිධ සංඛ්‍යා භාවිතා කරයි - නිදසුනක් ලෙස C # සම්පාදකයා (නිර්නාමික වර්ග සඳහා) 0x51ed270b බීජයක් සහ -1521134295 සාධකය භාවිතා කරයි.
මාක් ග්‍රෙවෙල්

76
E ලියාන්ඩ්‍රෝ ලෝපෙස්: සාමාන්‍යයෙන් සාධක ප්‍රමුඛ සංඛ්‍යා ලෙස තෝරාගනු ලබන්නේ එය isions ට්ටන ගණන කුඩා කරන බැවිනි.
ඇන්ඩ්‍රි රෙනියා

29
- ".! අපොයි පහසුව සඳහා, ඔබ ද ලබා == හා = ක්රියාකරුවන්, ප්රමුඛ විට සමාන වේ හා GethashCode සලකා බැලීමට ඉඩ": මයික්රොසොෆ්ට් අධෛර්යමත් අණුවල පැවැත්ම නොවන බව වස්තූන් ක්රියාකරු == ක්රියාත්මක - msdn.microsoft.com/en-us/library/ ms173147.aspx - "ක්‍රියාකරු == වෙනස් කළ නොහැකි අභිබවා යාම හොඳ අදහසක් නොවේ."
antiduh

137

GetHashCode()මාක් දැනටමත් සඳහන් කර ඇති නීතිවලට අමතරව, වස්තුවක ජීවිත කාලය තුළ හැෂ් කේතය වෙනස් නොවිය යුතු නිසා එය නිවැරදිව ක්‍රියාත්මක කිරීම ඉතා අසීරු ය . එබැවින් හැෂ් කේතය ගණනය කිරීම සඳහා භාවිතා කරන ක්ෂේත්‍ර වෙනස් කළ නොහැක.

මම අවසානයේ NHibernate සමඟ වැඩ කරන විට මෙම ගැටලුවට විසඳුමක් සොයා ගතිමි. මගේ ප්‍රවේශය වන්නේ වස්තුවේ හැඳුනුම්පතෙන් හැෂ් කේතය ගණනය කිරීමයි. හැඳුනුම්පත සැකසිය හැක්කේ ඉදිකිරීම්කරු වුවද ඔබට හැඳුනුම්පත වෙනස් කිරීමට අවශ්‍ය නම් එය ඉතා අසීරු නම්, ඔබට නව හැඳුනුම්පතක් ඇති නව වස්තුවක් නිර්මාණය කළ යුතු අතර එබැවින් නව හැෂ් කේතයක් ඇත. අහඹු ලෙස හැඳුනුම්පතක් ජනනය කරන පරාමිති රහිත ඉදිකිරීම්කරුවෙකු ඔබට ලබා දිය හැකි බැවින් මෙම ප්‍රවේශය GUID සමඟ වඩාත් හොඳින් ක්‍රියා කරයි.


20
@ වන්ජා. එය කළ යුතු යැයි මම විශ්වාස කරමි: ඔබ වස්තුව ශබ්ද කෝෂයකට එකතු කර පසුව වස්තුවෙහි හැඳුනුම්පත වෙනස් කරන්නේ නම්, පසුව ලබා ගැනීමේදී ඔබ එය ලබා ගැනීමට වෙනත් හැෂ් එකක් භාවිතා කරනු ඇත, එවිට ඔබට එය කිසි විටෙකත් ශබ්දකෝෂයෙන් ලබා ගත නොහැක.
ඇනෙව්ස්

75
GetHashCode () ක්‍රියාකාරීත්වය පිළිබඳ මයික්‍රොසොෆ්ට් ප්‍රලේඛනයෙහි සඳහන් වන්නේ හෝ වස්තුව හැෂ් එහි ජීවිත කාලය පුරාම ස්ථාවරව පැවතිය යුතු බව සඳහන් නොකරයි. ඇත්ත වශයෙන්ම, එය එසේ නොවිය හැකි එක් අවසර ලත් අවස්ථාවක් විශේෂයෙන් විස්තර කරයි : “වස්තුවක් සඳහා වන GetHashCode ක්‍රමය වස්තුවේ සමාන ක්‍රමයේ ප්‍රතිලාභ අගය තීරණය කරන වස්තු තත්වයට කිසිදු වෙනස් කිරීමක් සිදු නොවන තාක් කල් එකම හැෂ් කේතය නැවත ලබා දිය යුතුය. . "
පීටර්ඇලන් වෙබ්

37
"වස්තුවක ජීවිත කාලය තුළ හැෂ් කේතය වෙනස් නොවිය යුතුය" - එය සත්‍ය නොවේ.
එළිදරව්ව

7
එය කීමට වඩා හොඳ ක්‍රමයක් වන්නේ “එකතුවක් සඳහා යතුරක් ලෙස වස්තුව භාවිතා කරන කාල සීමාව තුළ හැෂ් කේතය (හෝ සමානව ඉවත් කිරීම) වෙනස් විය යුතුය” එබැවින් ඔබ වස්තුව ශබ්ද කෝෂයකට යතුරක් ලෙස එකතු කරන්නේ නම් ඔබ එය සහතික කළ යුතුය GetHashCode සහ Equals ඔබ ශබ්ද කෝෂයෙන් වස්තුව ඉවත් කරන තුරු දී ඇති ආදානය සඳහා ඔවුන්ගේ ප්‍රතිදානය වෙනස් නොකරනු ඇත.
ස්කොට් චේම්බර්ලින්

11
C ස්කොට්චම්බර්ලයින් ඔබේ අදහසෙහි ඔබට අමතක වී නැති බව මම සිතමි, එය එසේ විය යුතුය: "එකතුවක් සඳහා යතුරක් ලෙස වස්තුව භාවිතා කරන කාල සීමාව තුළ හැෂ් කේතය (හෝ සමානව ඉවත් කිරීම) වෙනස් නොවිය යුතුය". හරිද?
ස්ටැන් ප්‍රොකොප්

59

සමානාත්මතාවය ඉක්මවා යාමෙන් ඔබ මූලිකවම කියා සිටින්නේ යම් වර්ගයක අවස්ථා දෙකක් සංසන්දනය කරන්නේ කෙසේද යන්න වඩා හොඳින් දන්නා තැනැත්තා ඔබ බවය, එබැවින් ඔබ හොඳම හැෂ් කේතය ලබා දීමට හොඳම අපේක්ෂකයා වනු ඇත.

ReSharper ඔබ වෙනුවෙන් GetHashCode () ශ්‍රිතයක් ලියන ආකාරය පිළිබඳ උදාහරණය මෙයයි:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

ඔබට පෙනෙන පරිදි එය පන්තියේ සියලුම ක්ෂේත්‍ර මත පදනම්ව හොඳ හැෂ් කේතයක් අනුමාන කිරීමට උත්සාහ කරයි, නමුත් ඔබේ වස්තුවේ වසම හෝ අගය පරාසයන් ඔබ දන්නා බැවින් ඔබට තවමත් වඩා හොඳ එකක් ලබා දිය හැකිය.


7
මෙය සැමවිටම ශුන්‍ය නොවේද? ප්‍රති result ලය 1 දක්වා ආරම්භ කළ යුතුය! තවත් අර්ධ කොලන් කිහිපයක් අවශ්‍ය වේ.
සෑම් මැක්රිල්

16
XOR ක්‍රියාකරු (^) කරන්නේ කුමක්දැයි ඔබ දන්නවාද?
ස්ටීවන් ඩ rew

1
මා පැවසූ පරිදි, R # ඔබ වෙනුවෙන් ලියන්නේ මෙයයි (අවම වශයෙන් එය 2008 දී නැවත කළේ එයයි). නිසැකවම, මෙම ස්නිපටය ක්‍රමලේඛකයා විසින් යම් ආකාරයකින් අතුගා දැමීමට අදහස් කරයි. අතුරුදහන් වූ අර්ධ කොලන් සම්බන්ධයෙන් ගත් කල ... ඔව්, දෘශ්‍ය ස්ටුඩියෝ හි කලාපීය තේරීමකින් කේතය පිටපත් කළ විට මම ඒවා අතහැර දැමූ බවක් පෙනේ. මම හිතුවා මිනිස්සු මේ දෙකම තේරුම් ගනීවි කියලා.
උගුල

3
AmSamMackrill නැතිවූ අර්ධ කොලොන්වල මම එකතු කර ඇත්තෙමි.
මැතිව් මර්ඩොක්

5
මෙයට @SamMackrill, එය සෑම විටම 0 හැරී එන්නේ නැත 0 ^ a = a, ඒ නිසා 0 ^ m_someVar1 = m_someVar1. ඔහු විසින් ආරම්භක අගය ද resultනියම කළ m_someVar1හැකිය.
මිලී ස්මිත්

41

අභිබවා යන nullවිට විරුද්ධ පරාමිතිය පරීක්ෂා කිරීමට කරුණාකර අමතක නොකරන්න Equals(). තවද වර්ගය සංසන්දනය කරන්න.

public override bool Equals(object obj)
{
    Foo fooItem = obj as Foo;

    if (fooItem == null)
    {
       return false;
    }

    return fooItem.FooId == this.FooId;
}

මෙයට හේතුව: Equalsසාපේක්ෂව සාවද්‍ය ලෙස ආපසු යා යුතුය null. Http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx ද බලන්න


6
වර්ගය සඳහා මෙම සොයමු උපපංතිය එය ම සංසන්දනය (එනම් base.Equals (එය විවෘත)) කොටසක් ලෙස සමාන වේ ක්රමය superclass යොමු කරන තත්වයක් තුළ අසාර්ථක වනු ඇත - ඒ වෙනුවට ලෙස යොදා ගත යුතුය
sweetfa

we ස්වීට්ෆා: එය උප පංතියේ සමාන ක්‍රමය ක්‍රියාත්මක කරන ආකාරය මත රඳා පවතී. එයට base.Equals ((BaseType) obj)) ලෙසද හැඳින්විය හැකිය.
huha

2
නැත එය සිදු නොවේ: msdn.microsoft.com/en-us/library/system.object.gettype.aspx . ඊට අමතරව, ක්‍රමවේදයක් ක්‍රියාත්මක කිරීම අසාර්ථක හෝ සාර්ථක නොවිය යුතුය. වස්තුවක ඇති ධාවන-වර්ගය සමහර baseclass ක උපපංතිය වේ නම්, එවිට එම baseclass ක තැනෙන්නේ () නම් සැබෑ යළි උදා කළ යුතුයි objසැබවින්ම සමාන වේ thisයන baseclass ක (සමාන වේ ආකාරය උනත්) නම් විය.
බ්‍රහස්පති

2
fooItemඉහළට ගෙනයාම සහ පසුව එය ශුන්‍යදැයි පරීක්ෂා කිරීම ශුන්‍ය හෝ වැරදි වර්ගයකදී වඩා හොඳින් ක්‍රියා කරයි.
ඉලිඩාන් එස් 4 ට මොනිකා නැවත අවශ්‍යයි

1
@ 40 ඇල්ෆා හොඳයි, ඔව්, එවිට obj as Fooඅවලංගු වේ.
ඉලිඩාන් එස් 4 ට මොනිකා නැවත අවශ්‍යයි

36

කොහොමද:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

කාර්ය සාධනය උපකල්පනය කිරීමක් නොවේ :)


1
erm - නමුත් ඔබ int පදනම් කරගත් ක්‍රමයක් සඳහා නූලක් ආපසු
යවයි

32
නැත, ඔහු සංගීත වස්තුවෙන් GetHashCode () අමතයි.
රිචඩ් ක්ලේටන්

3
මෙය මා කැමති තරම් වේගවත් වනු ඇතැයි මම අපේක්ෂා නොකරමි, වටිනාකම් වර්ග සඳහා සම්බන්ධ වන බොක්සිං සඳහා පමණක් නොව, එහි ක්‍රියාකාරිත්වය සඳහා ද string.Format. මා දුටු තවත් භූගෝලීය එකක් new { prop1, prop2, prop3 }.GetHashCode(). මේ දෙක අතර මන්දගාමී වන්නේ කුමන එකක් දැයි අදහස් දැක්විය නොහැක. මෙවලම් අනිසි ලෙස භාවිතා නොකරන්න.
නව්ෆල්

16
මේ සඳහා සැබෑ ආපසු { prop1="_X", prop2="Y", prop3="Z" }හා { prop1="", prop2="X_Y", prop3="Z_" }. ඔබට එය අවශ්‍ය නොවනු ඇත.
voetsjoeba

2
ඔව්, ඔබට සැමවිටම යටි ඉරි සහිත සංකේතය එතරම් සුලභ නොවන දෙයක් සමඟ ප්‍රතිස්ථාපනය කළ හැකිය (උදා: •, ▲,,,,) සහ ඔබේ පරිශීලකයින් මෙම සංකේත භාවිතා නොකරනු ඇතැයි බලාපොරොත්තු වෙමු ... :)
ලුඩ්මිල් ටින්කොව්

14

අපට මුහුණ දීමට ගැටලු දෙකක් තිබේ.

  1. GetHashCode()වස්තුවෙහි කිසියම් ක්ෂේත්‍රයක් වෙනස් කළ හැකි නම් ඔබට සංවේදීතාවයක් ලබා දිය නොහැක . බොහෝ විට වස්තුවක් රඳා පවතින එකතුවක කිසි විටෙකත් භාවිතා නොකරනු ඇත GetHashCode(). එබැවින් ක්‍රියාත්මක කිරීමේ පිරිවැය GetHashCode()බොහෝ විට එය වටින්නේ නැත, නැතහොත් එය කළ නොහැකි ය.

  2. කවුරුහරි ඔබේ වස්තුව ඇමතුමකට එකතු කර නිවැරදි ආකාරයකින් හැසිරීමට GetHashCode()ඉඩ Equals()නොදී ඔබ ඉක්මවා ගියහොත් GetHashCode(), එම පුද්ගලයා ගැටලුව සොයා ගැනීමට දින ගණනක් ගත කළ හැකිය.

එබැවින් පෙරනිමියෙන් මම එසේ කරමි.

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null)
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}

5
GetHashCode වෙතින් ව්‍යතිරේකයක් විසි කිරීම වස්තු කොන්ත්‍රාත්තුව උල්ලං is නය කිරීමකි. GetHashCodeසමාන වස්තු දෙකක් එකම හැෂ් කේතය ආපසු ලබා දෙන ශ්‍රිතයක් අර්ථ දැක්වීමේ දුෂ්කරතාවයක් නොමැත ; return 24601;හා return 8675309;දෙකම වලංගු නිර්මාණයන් වනු ඇත GetHashCode. කාර්ය සාධනය Dictionaryයහපත් වන්නේ අයිතම ගණන කුඩා වූ විට පමණක් වන අතර, අයිතම ගණන විශාල වුවහොත් එය ඉතා නරක වනු ඇත, නමුත් එය ඕනෑම අවස්ථාවක නිවැරදිව ක්‍රියා කරයි.
සුපර් කැට්

3
up සුපර්කැට්, හැෂ් කේතය කිසි විටෙකත් වෙනස් නොවිය යුතු බැවින්, වස්තුවෙහි හඳුනාගැනීමේ ක්ෂේත්‍ර වෙනස් විය හැකි නම් GetHashCode සංවේදී ආකාරයකින් ක්‍රියාත්මක කළ නොහැක. ඔබ කියන දේ කිරීමෙන් යමෙකුට කාර්ය සාධන ගැටලුව සොයා ගැනීමට දින ගණනාවක් ගත කිරීමට සිදුවිය හැකි අතර, පසුව ශබ්ද කෝෂ භාවිතය ඉවත් කිරීම සඳහා විශාල පද්ධතියක් නැවත සැලසුම් කිරීම.
ඉයන් රින්ග්‍රෝස්

2
සමාන () අවශ්‍ය යැයි මා විසින් නිර්වචනය කරන ලද සියලුම පංති සඳහා මම මේ වගේ දෙයක් කිරීමට පුරුදුව සිටියෙමි. තවද, මම කිසි විටෙකත් එම වස්තුව එකතුවක යතුරක් ලෙස භාවිතා නොකරමි. ඊට පස්සේ දවසක් මම DevExpress XtraGrid පාලනයට ආදාන ලෙස එවැනි වස්තුවක් භාවිතා කළ වැඩසටහනක් බිඳ වැටුණා. මගේ පිටුපසට පිටුපසින් එක්ස්ට්‍රාග්‍රිඩ් හැෂ් ටේබල් එකක් හෝ මගේ වස්තූන් මත පදනම් වූ යමක් නිර්මාණය කරමින් සිටි බව පෙනේ. මම මේ පිළිබඳව DevExpress සහය දක්වන පුද්ගලයින් සමඟ සුළු තර්කයකට පැටලුණා. නොදන්නා පාරිභෝගිකයින් අපැහැදිලි ක්‍රමවේදයක් ක්‍රියාත්මක කිරීම මත ඔවුන්ගේ සංරචකයේ ක්‍රියාකාරිත්වය සහ විශ්වසනීයත්වය පදනම් කර ගැනීම බුද්ධිමත් නොවන බව මම කීවෙමි.
රෙනීපෙට්

DevExpress ජනතාව තරමක් නින්දිත විය, මූලික වශයෙන් කියන්නේ GetHashCode () ක්‍රමයට ව්‍යතිරේකයක් විසි කිරීමට මම මෝඩයෙකු විය යුතු බවයි. GetHashCode () මත යැපීමෙන් තොරව අත්තනෝමතික වස්තූන්ගේ ශබ්ද කෝෂයක් ගොඩනගන්නේ කෙසේද යන්න විස්තර කරන මාක් ග්‍රෙවෙල් වෙනත් ත්‍රෙඩ් එකක ඔවුන් සිහිපත් කරයි - ඔහු එය කළ ආකාරය මතක නැත. නමුත්.
රෙනීපෙට්

4
EnnRenniePet, ව්‍යතිරේකයක් විසි කිරීම නිසා ක්‍රෂ් එකක් තිබීම වඩා හොඳ විය යුතුය, පසුව අවලංගු ක්‍රියාත්මක කිරීමක් හේතුවෙන් දෝෂයක් සොයා ගැනීම ඉතා අසීරු විය යුතුය.
ඉයන් රින්ග්‍රෝස්

12

රාමුවට අවශ්‍ය වන්නේ එකම වස්තු දෙකක් එකම හැෂ් කේතයක් තිබිය යුතු බැවිනි. වස්තූන් දෙකක විශේෂ සංසන්දනයක් කිරීම සඳහා ඔබ සමාන ක්‍රමය ඉක්මවා ගියහොත් සහ එම වස්තූන් දෙක ක්‍රමවේදය එක හා සමාන යැයි සලකන්නේ නම්, එම වස්තු දෙකේ හැෂ් කේතය ද සමාන විය යුතුය. (ශබ්ද කෝෂ සහ හැෂ්ටේබල් මෙම මූලධර්මය මත රඳා පවතී).


11

ඉහත පිළිතුරු එකතු කිරීම සඳහා:

ඔබ සමානකම් ඉක්මවා නොයන්නේ නම් පෙරනිමි හැසිරීම නම් වස්තූන්ගේ යොමු කිරීම් සැසඳීමයි. හැෂ්කෝඩ් සඳහාද එය අදාළ වේ - පෙරනිමි implmentation සාමාන්‍යයෙන් යොමු කිරීමේ මතක ලිපිනය මත පදනම් වේ. ඔබ සමානාත්මතාවය ඉක්මවා ගිය නිසා එයින් අදහස් කරන්නේ නිවැරදි හැසිරීම යනු ඔබ සමානාත්මතාවයේ ක්‍රියාත්මක කළ ඕනෑම දෙයක් සැසඳීම මිස යොමු කිරීම් නොවේ, එබැවින් ඔබ හැෂ් කේතය සඳහාද එසේ කළ යුතුය.

ඔබේ පන්තියේ සේවාදායකයින් හැෂ් කේතයට සමාන ක්‍රමයට සමාන තර්කනයක් බලාපොරොත්තු වනු ඇත, උදාහරණයක් ලෙස IEqualityComparer භාවිතා කරන ලින්ක් ක්‍රම පළමුව හැෂ් කේත සංසන්දනය කරන අතර ඒවා සමාන නම් පමණක් ඔවුන් වඩා මිල අධික විය හැකි සමාන () ක්‍රමය සංසන්දනය කරයි. ධාවනය කිරීමට, අපි හැෂ්කෝඩ් ක්‍රියාත්මක නොකළේ නම්, සමාන වස්තුවකට විවිධ හැෂ් කේත ඇත (ඒවාට වෙනස් මතක ලිපිනයක් ඇති නිසා) සහ සමාන නොවන බව වැරදියට තීරණය වේ (සමාන () පහර දෙන්නේ නැත).

ඊට අමතරව, ඔබ ඔබේ වස්තුව ශබ්දකෝෂයක භාවිතා කළේ නම් එය සොයා ගැනීමට නොහැකි වනු ඇත (එය එක් හැෂ් කේතයක් මඟින් ඇතුළත් කර ඇති නිසා සහ ඔබ එය සොයන විට පෙරනිමි හැෂ් කේතය බොහෝ විට වෙනස් වන අතර නැවත සමාන වේ () මාක් ග්‍රෙවෙල් ඔහුගේ පිළිතුරෙහි පැහැදිලි කර ඇති පරිදි, ඔබ සමාන ශබ්ද වලට ඉඩ නොදිය යුතු ශබ්ද කෝෂය හෝ හැෂ්සෙට් සංකල්පය උල්ලං violation නය කිරීමක් හඳුන්වා දෙයි - ඔබ දැනටමත් ප්‍රකාශ කර ඇත්තේ ඔබ සමානකම් ඉක්මවා යන විට එම වස්තූන් එක හා සමාන බවයි. අද්විතීය යතුරක් ඇතැයි සිතන දත්ත ව්‍යුහයක මේ දෙකම වෙනස් යතුරු ලෙස අවශ්‍ය නොවේ.නමුත් ඒවාට වෙනස් හැෂ් කේතයක් ඇති බැවින් “එකම” යතුර වෙනස් එකක් ලෙස ඇතුළත් වේ.


8

ශබ්ද කෝෂය ශබ්දකෝෂය, හැෂ්ටබල්, හැෂ්සෙට් වැනි හැෂ් මත පදනම් වූ එකතු කිරීම් සඳහා භාවිතා කරයි. මෙම කේතයේ අරමුණ විශේෂිත වස්තුවකට නිශ්චිත කාණ්ඩයකට (බාල්දියට) ඇතුළත් කිරීමෙන් ඉතා ඉක්මණින් පූර්ව වර්ග කිරීම ය. මෙම වස්තුව ඔබට හැෂ්-එකතුවෙන් නැවත ලබා ගැනීමට අවශ්‍ය වූ විට එය සොයා ගැනීමට මෙම පෙර-වර්ග කිරීම බෙහෙවින් උපකාරී වේ, මන්ද කේතයට ඔබේ වස්තුව එහි ඇති සියලුම වස්තූන් වෙනුවට එක් බාල්දියකින් සෙවිය යුතු බැවිනි. හැෂ් කේත වඩා හොඳින් බෙදා හැරීම (වඩා හොඳ සුවිශේෂත්වය) වේගයෙන් ලබා ගැනීම. සෑම වස්තුවකටම අද්විතීය හැෂ් කේතයක් ඇති පරිපූර්ණ තත්වයකදී, එය සොයා ගැනීම O (1) මෙහෙයුමකි. බොහෝ අවස්ථාවල එය O (1) වෙත ළඟා වේ.


7

එය අනිවාර්යයෙන්ම වැදගත් නොවේ; එය ඔබගේ එකතු කිරීම්වල ප්‍රමාණය සහ කාර්ය සාධන අවශ්‍යතා මත රඳා පවතී සහ කාර්ය සාධන අවශ්‍යතා ඔබ නොදන්නා පුස්තකාලයක ඔබේ පන්තිය භාවිතා කරන්නේද යන්න මත රඳා පවතී. මගේ එකතු කිරීමේ ප්‍රමාණය ඉතා විශාල නොවන බව මම නිතරම දනිමි. පරිපූර්ණ හැෂ් කේතයක් නිර්මාණය කිරීමෙන් ලබාගත් කාර්යසාධනයේ මයික්‍රෝ තත්පර කිහිපයකට වඩා මගේ කාලය වටිනවා; එබැවින් (සම්පාදකයාගේ කරදරකාරී අනතුරු ඇඟවීමෙන් මිදීමට) මම සරලවම භාවිතා කරන්නේ:

   public override int GetHashCode()
   {
      return base.GetHashCode();
   }

(ඇත්ත වශයෙන්ම මට අනතුරු ඇඟවීම ක්‍රියා විරහිත කිරීමට # ප්‍රාග්මා එකක් භාවිතා කළ හැකි නමුත් මම මේ ආකාරයට කැමැත්තෙමි.)

මෙහි සිටින අනෙක් අය සඳහන් කර ඇති සියලුම ගැටළු වලට වඩා ඔබට කාර්ය සාධනය අවශ්‍ය යැයි ඔබ සිතන විට, ඇත්ත වශයෙන්ම. වැදගත්ම දේ - එසේ නොමැතිනම් හැෂ් කට්ටලයකින් හෝ ශබ්ද කෝෂයකින් අයිතම ලබා ගැනීමේදී ඔබට වැරදි ප්‍රති results ල ලැබෙනු ඇත: හැෂ් කේතය වස්තුවක ආයු කාලය සමඟ වෙනස් නොවිය යුතුය (වඩාත් නිවැරදිව, හැෂ් කේතය අවශ්‍ය වන කාලය තුළ, එනම් සිටියදී ශබ්දකෝෂයක යතුරක්): නිදසුනක් ලෙස, අගය පොදු බැවින් පහත සඳහන් දේ වැරදියි, එම නිසා නිදසුනෙහි ජීවිත කාලය තුළ පන්තියට බාහිරව වෙනස් කළ හැකිය, එබැවින් ඔබ එය හැෂ් කේතයේ පදනම ලෙස භාවිතා නොකළ යුතුය:


   class A
   {
      public int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
      }
   }    

අනෙක් අතට, අගය වෙනස් කළ නොහැකි නම් එය භාවිතා කිරීම සුදුසු ය:


   class A
   {
      public readonly int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //OK  Value is read-only and can't be changed during the instance's life time
      }
   }

3
පහත් කොට ඇත. මෙය සරල වැරදිය. මයික්‍රොසොෆ්ට් පවා MSDN හි සඳහන් කරයි ( msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) හි සඳහන් වන්නේ GetHashCode හි වටිනාකම වෙනස් විය යුත්තේ වස්තුවේ තත්වය වෙනස් වන විට ඇමතුමක ප්‍රතිලාභ වටිනාකමට බලපාන බවයි. සමාන () වෙත, සහ එහි උදාහරණවල පවා එය ප්‍රසිද්ධියේ වෙනස් කළ හැකි අගයන් මත සම්පූර්ණයෙන්ම රඳා පවතින GetHashCode ක්‍රියාත්මක කිරීම් පෙන්වයි.
සෙබස්තියන් පීආර් ජින්ජර්

සෙබස්තියන්, මම එකඟ නොවෙමි: ඔබ හැෂ් කේත භාවිතා කරන එකතුවකට වස්තුවක් එකතු කළහොත් එය හැෂ් කේතය මත රඳා පවතින බඳුනකට දමනු ලැබේ. ඔබ දැන් හැෂ් කේතය වෙනස් කළහොත් වැරදි බඳුන සෙවීම නිසා ඔබට නැවත වස්තුව එකතුවෙහි සොයාගත නොහැක. මෙය ඇත්ත වශයෙන්ම අපගේ කේතයේ සිදුවී ඇති දෙයක් වන අතර එය පෙන්වා දීමට අවශ්‍ය බව මට පෙනී ගියේ එබැවිනි.
ILoveFortran

2
සෙබස්තියන්, ඊට අමතරව, GetHashCode () වෙනස් විය යුතු ( msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) සබැඳියේ ප්‍රකාශයක් මට නොපෙනේ . ඊට ප්‍රතිවිරුද්ධව - සමාන තර්කයක් සඳහා සමාන අගයක් ලබා දෙන තාක් කල් එය වෙනස් නොවිය යුතුය: “වස්තුවක් සඳහා වන GetHashCode ක්‍රමය මඟින් ප්‍රතිලාභ අගය තීරණය කරන වස්තු තත්වයට කිසිදු වෙනස් කිරීමක් සිදු නොවන තාක් කල් එකම හැෂ් කේතය නැවත ලබා දිය යුතුය. වස්තුවේ සමානාත්මතා ක්‍රමවේදය.
ILoveFortran

2
O ජෝවා, ඔබ නිෂ්පාදකයා / ක්‍රියාත්මක කරන්නා සමඟ ගිවිසුමේ සේවාදායකයා / පාරිභෝගික පාර්ශවය ව්‍යාකූල කරයි. මම මේ කතා කරන්නේ GetHashCode () අභිබවා යන ක්‍රියාත්මක කරන්නාගේ වගකීම ගැන ය. ඔබ කතා කරන්නේ පාරිභෝගිකයා, වටිනාකම භාවිතා කරන තැනැත්තා ගැන ය.
ILoveFortran

1
සම්පූර්ණ වරදවා වටහා ගැනීම ... :) සත්‍යය නම් වස්තුවේ අනන්‍යතාවයට රාජ්‍යය අදාල නොවේ නම් වස්තුවේ තත්වය වෙනස් වන විට හැෂ් කේතය වෙනස් විය යුතුය. එසේම, ඔබ කිසි විටෙකත් ඔබේ එකතුවෙහි යතුරක් ලෙස MUTABLE වස්තුවක් භාවිතා නොකළ යුතුය. මේ සඳහා කියවීමට පමණක් ඇති වස්තු භාවිතා කරන්න. GetHashCode, Equals ... සහ මේ මොහොතේ මට මතක නැති වෙනත් ක්‍රම කිහිපයක් විසි නොකළ යුතුය.
ඩාර්ලෝව්

2

සමාන () මගින් අර්ථ දක්වා ඇති පරිදි වස්තු දෙකක් සමාන නම් ඒවා එකම හැෂ් කේතය ආපසු ලබා දිය යුතු බවට ඔබ සැමවිටම සහතික විය යුතුය. වෙනත් සමහර අදහස් දැක්වෙන පරිදි, න්‍යාය අනුව මෙය හැෂ්සෙට් හෝ ශබ්ද කෝෂය වැනි හැෂ් පදනම් කරගත් බහාලුමක් තුළ කිසි විටෙකත් භාවිතා නොකරන්නේ නම් මෙය අනිවාර්ය නොවේ. සෑම විටම මෙම රීතිය අනුගමනය කරන ලෙස මම ඔබට උපදෙස් දෙමි. හේතුව හුදෙක් කාර්ය සාධනය වැඩි දියුණු කිරීම හෝ කේත අර්ථ නිරූපණය වඩා හොඳ ආකාරයකින් ගෙන ඒමේ හොඳ අභිප්‍රාය ඇතිව එක් වර්ගයක සිට තවත් වර්ගයකට එකතුවක් වෙනස් කිරීම කෙනෙකුට පහසු නොවන බැවිනි.

උදාහරණයක් ලෙස, අපි සමහර වස්තු ලැයිස්තුවක තබා ඇතැයි සිතමු. කලකට පසු යමෙකුට වැටහෙන්නේ නිදසුනක් ලෙස වඩා හොඳ සෙවුම් ලක්ෂණ නිසා හැෂ්සෙට් වඩා හොඳ විකල්පයක් බවයි. මෙය අපට කරදරයකට පත්විය හැකි අවස්ථාවකි. ලැයිස්තුව අභ්‍යන්තරව සුපුරුදු සමානාත්මතා සංසන්දකය භාවිතා කරයි, එයින් අදහස් වන්නේ ඔබේ නඩුවේ සම සමාන වන අතර හැෂ්සෙට් GetHashCode () භාවිතා කරයි. දෙදෙනා වෙනස් ලෙස හැසිරෙන්නේ නම්, ඔබේ වැඩසටහනද එසේමය. එවැනි ගැටළු නිරාකරණය සඳහා පහසුම නොවන බව මතක තබා ගන්න.

මම මෙම හැසිරීම වෙනත් GetHashCode () අන්තරායන් සමඟ සාරාංශ කොට ඇත බ්ලොග් අතර එහිදී ඔබට තවත් උදාහරණ සහ පැහැදිලි කිරීම් සොයාගත හැකිය.


2

අභිබවා .NET 4.7යාමේ වඩාත් කැමති ක්‍රමය අනුව GetHashCode()පහත දැක්වේ. පැරණි .NET අනුවාදයන් ඉලක්ක කරන්නේ නම්, System.ValueTuple nuget පැකේජය ඇතුළත් කරන්න .

// C# 7.0+
public override int GetHashCode() => (FooId, FooName).GetHashCode();

කාර්ය සාධනය අනුව, මෙම ක්‍රමය බොහෝ සංයුක්ත හැෂ් කේත ක්‍රියාත්මක කිරීම් අභිබවා යනු ඇත . මෙම ValueTuple යනු structඑසේ ඕනෑම කුණු නැති වෙන්නේ නැහැ, සහ යටින් ඇල්ගොරිතමය වේගයෙන් එය ලැබෙන පරිදි වේ.


-1

මුල් GetHashCode () මඟින් වස්තුවේ මතක ලිපිනය ලබා දෙන බව මගේ වැටහීමයි, එබැවින් ඔබට විවිධ වස්තු දෙකක් සංසන්දනය කිරීමට අවශ්‍ය නම් එය අභිබවා යාම අත්‍යවශ්‍ය වේ.

සංස්කරණය කරන ලදි: එය වැරදියි, මුල් GetHashCode () ක්‍රමයට අගයන් 2 ක සමානාත්මතාවය සහතික කළ නොහැක. සමාන වස්තූන් එකම හැෂ් කේතය ලබා දුන්නද.


-6

පරාවර්තනය භාවිතා කිරීමට පහළින් මට වඩා හොඳ විකල්පයක් ලෙස පෙනේ පොදු දේපල සලකා බැලීමේදී ඔබට දේපල එකතු කිරීම / ඉවත් කිරීම ගැන කරදර විය යුතු නැත (එතරම් පොදු තත්වයක් නොතිබුණද). මෙය වඩාත් හොඳින් ක්‍රියාත්මක වන බව මට පෙනී ගියේය. (විකර්ණ නැවතුම් ඔරලෝසුව භාවිතා කරන කාලය හා සසඳන විට).

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }

13
GetHashCode () ක්‍රියාත්මක කිරීම ඉතා සැහැල්ලු වනු ඇතැයි අපේක්ෂා කෙරේ. දහස් ගණනක් ඇමතුම් වල StopWatch සමඟ පරාවර්තනය භාවිතා කිරීම සැලකිය යුතු යැයි මට විශ්වාස නැත, නමුත් එය නිසැකවම මිලියන ගණනක් වේ (ශබ්දකෝෂයක් ලැයිස්තුවෙන් ජනගහනය කිරීම ගැන සිතන්න).
bohdan_trotsenko
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.