ã¯ããã«
ãã®èšäºã¯ã.NETãã©ãããã©ãŒã ã§ã®ããã·ã¥ã³ãŒãã®çæã«çŠç¹ãåœãŠãŠããŸãã ãã®ãããã¯ã¯éåžžã«èå³æ·±ããã®ã§ãããèªå°å¿ã®ãã.NETéçºè ãªã誰ã§ãç¥ã£ãŠããã¯ãã§ãã ãããè¡ããïŒ
ãã£ãŒã«ã以å€ã®ãªããžã§ã¯ãã«ã¯äœãä¿åãããŸããïŒ
èšäºã®æåã«ããã£ãŒã«ãã«å ããŠåç §åã®ãªããžã§ã¯ãã«ä¿åãããŠãããã®ãåŠç¿ããŸãã
åç §ã¿ã€ãã®åãªããžã§ã¯ãã«ã¯ãããããŒïŒããããŒïŒãšåŒã°ãã2ã€ã®ãã£ãŒã«ãããããŸãããã®ãªããžã§ã¯ãã®ã¿ã€ããžã®ãã€ã³ã¿ãŒïŒMethodTablePointerïŒãšãåæã€ã³ããã¯ã¹ïŒSyncBlockIndexïŒã§ãã
圌ãã¯äœã®ããã«ïŒ
æåã®ãã£ãŒã«ãã¯ãå管ç察象ãªããžã§ã¯ããå®è¡æã«ãã®ã¿ã€ãã«é¢ããæ å ±ãæäŸã§ããããã«ããããã«å¿ èŠã§ããã€ãŸãã次ã®ã¿ã€ãã次ã ã«é ãããšã¯ã§ããŸãããããã¯ã¿ã€ãã»ãŒãã®ããã«è¡ãããŸãã ãã®ãã€ã³ã¿ãŒã¯ãã¡ãœããã®åçãã£ã¹ããããå®è£ ããããã«ã䜿çšãããŸã;å®éããã®ãªããžã§ã¯ãã®ã¡ãœããã¯ãããéããŠåŒã³åºãããŸãã Object.GetTypeã¡ãœããã¯ãå®éã«ã¯MethodTablePointerãã€ã³ã¿ãŒãæ£ç¢ºã«è¿ããŸãã
2çªç®ã®ãã£ãŒã«ãã¯ããã«ãã¹ã¬ããç°å¢ã«å¿ èŠã§ããã€ãŸããåãªããžã§ã¯ããã¹ã¬ããã»ãŒãã§äœ¿çšã§ããããã«ããŸãã
CLRãèªã¿èŸŒãŸãããšãããããåæãããã¯ã®ããŒã«ãäœæãããŸãããããã®åæãããã¯ã®éåžžã®é åãšèšããŸãã ãªããžã§ã¯ãããã«ãã¹ã¬ããç°å¢ã§åäœããå¿ èŠãããå ŽåïŒããã¯Monitor.Enterã¡ãœãããŸãã¯CïŒããã¯èšèªæ§æã䜿çšããŠè¡ãããŸãïŒãCLRã¯ãã®ãªã¹ãã§ç©ºãåæãããã¯ãæ¢ãããã®ã€ã³ããã¯ã¹ããªããžã§ã¯ãããããŒã®åããã£ãŒã«ãã«æžã蟌ã¿ãŸãã ãªããžã§ã¯ãããã«ãã¹ã¬ããç°å¢ãå¿ èŠãšããªããªããšããã«ãCLRã¯ãã®ãã£ãŒã«ãã«-1ã®å€ãå²ãåœãŠãã ãã§ãåæãããã¯ã解æŸããŸãã
åæãããã¯ã¯ãå®éã«ã¯C ++ããã®ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®æ°ããå身ã§ãã CLRã®äœæè ã¯ãã»ãšãã©ã®ãªããžã§ã¯ãããã«ãã¹ã¬ããç°å¢ããŸã£ãã䜿çšããŠããªãããšãèæ ®ãããšãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³æ§é ãå管ç察象ãªããžã§ã¯ãã«é¢é£ä»ããã«ã¯è²»çšããããããããšæããŸããã
ç¶æ³ãããããç解ããã«ã¯ã次ã®å³ãèæ ®ããŠãã ããã

ãã®å³ã¯ãObjectTableãšObjectTableãåãåãæããŠãããããObjectAãšObjectBãåãåã§ããããšã瀺ããŠããŸãã ObjectCã¯ç°ãªãã¿ã€ãã§ãã ãŸããObjectAãšObjectCãåæãããã¯ã®ããŒã«ã䜿çšããããšãããããŸããã€ãŸããå®éã«ã¯ãã«ãã¹ã¬ããç°å¢ã䜿çšããŸãã ObjectBã¯ãSyncBlockIndex = -1ã§ãããããããŒã«ã䜿çšããŸããã
ãªããžã§ã¯ãã®ä¿åæ¹æ³ã調ã¹ãåŸãããã·ã¥ã³ãŒãã®çæã«é²ãããšãã§ããŸãã
GetHashCodeãåç §åãšé£æºããæ¹æ³
GetHashCodeã¡ãœããããããŒãžããŒãå ã®ãªããžã§ã¯ãã®ã¢ãã¬ã¹ãè¿ããšããäºå®ã¯ç¥è©±ã§ãã ããã¯ããã®äžè²«æ§ã®èŠ³ç¹ãããã¬ããŒãžã³ã¬ã¯ã¿ãŒãããŒãã®å§çž®ããªããžã§ã¯ãã®ã·ãããããã«å¿ããŠãããã®ãã¹ãŠã®ã¢ãã¬ã¹ãå€æŽããããšã¯ã§ããŸããã
ãã¬ãŒã ã¯ãŒã¯ã®æåã®ããŒãžã§ã³ã§ã¯ãSyncBlockã®ããªãŒã€ã³ããã¯ã¹ãåç §åã®ããã·ã¥ã³ãŒããšããŠäœ¿çšãããŠãããããSyncBlockãšã¯äœãã説æããŠèšäºãå§ããã®ã¯ç¡é§ã§ã¯ãããŸããã§ããã ãããã£ãŠã.NET 1.0ããã³.NET 1.1ã§ã¯ãGetHashCodeã¡ãœãããåŒã³åºããšãSyncBlockãäœæãããSyncBlockIndexãã£ãŒã«ãã®ãªããžã§ã¯ãããããŒã«ãã®ã€ã³ããã¯ã¹ãäœæãããŸããã ç解ã§ããããã«ãããã¯ããã·ã¥é¢æ°ã®é©åãªå®è£ ã§ã¯ãããŸããããŸããã¡ã¢ãªãå æããäžå¿ èŠãªå éšæ§é ãäœæããããã®äœæã«æéã浪費ãããŸãã ããã«ããã°ãžã®ãªã³ã¯ããããŸããCLRéçºè ã®1人ãããã®ãããªå®è£ ã¯æªãããšã§ããã次ã®ããŒãžã§ã³ã§ãããå€æŽãããšèšããŸãã
.NET 2.0以éãããã·ã¥ã¢ã«ãŽãªãºã ãå€æŽãããŸããã çŸåšã§ã¯ãã¡ãœãããå®è¡ãããã¹ã¬ããã®ç®¡çèå¥åã䜿çšããŸãã SSCLI20ã§ã®å®è£ ãä¿¡ããŠããå Žåãã¡ãœããã¯æ¬¡ã®ããã«ãªããŸãã
inline DWORD GetNewHashCode() { // Every thread has its own generator for hash codes so that we won't get into a situation // where two threads consistently give out the same hash codes. // Choice of multiplier guarantees period of 2**32 - see Knuth Vol 2 p16 (3.2.1.2 Theorem A) DWORD multiplier = m_ThreadId*4 + 5; m_dwHashCodeSeed = m_dwHashCodeSeed*multiplier + 1; return m_dwHashCodeSeed; }
ãã®ããã«ãåã¹ã¬ããã«ã¯ããã·ã¥ã³ãŒãçšã®ç¬èªã®ãžã§ãã¬ãŒã¿ãŒãããããã2ã€ã®ã¹ã¬ãããåãããã·ã¥ã³ãŒããé£ç¶ããŠçæããç¶æ³ã«ã¯ãªããŸããã
åãšåæ§ã«ãããã·ã¥ã³ãŒãã¯1åèšç®ãããSyncBlockIndexãã£ãŒã«ãã®ãªããžã§ã¯ãããããŒã«æ ŒçŽãããŸãïŒããã¯CLRæé©åã§ãïŒã ããã§åé¡ã¯ãGetHashCodeã¡ãœãããåŒã³åºããåŸãåæã€ã³ããã¯ã¹ã䜿çšããå¿ èŠãããå Žåã¯ã©ãã§ããããã ã©ãã«èšé²ããŸããïŒ ãããŠãããã·ã¥ã³ãŒããã©ãããŸããïŒ
ãããã®è³ªåã«çããããã«ãSyncBlockã®æ§é ãæ€èšããŠãã ããã

GetHashCodeã¡ãœãããæåã«åŒã³åºããããšãCLRã¯ããã·ã¥ã³ãŒããèšç®ããSyncBlockIndexãã£ãŒã«ãã«å ¥åããŸãã SyncBlockããªããžã§ã¯ãã«é¢é£ä»ããããŠããå Žåãã€ãŸãSyncBlockIndexãã£ãŒã«ãã䜿çšãããŠããå ŽåãCLRã¯ããã·ã¥ã³ãŒããSyncBlockèªäœã«æžã蟌ã¿ãŸããå³ã¯ãããã·ã¥ã³ãŒãã®æ ŒçŽãæ åœããSyncBlockå ã®å Žæã瀺ããŠããŸãã SyncBlockã解æŸããããšããã«ãCLRã¯ããã·ã¥ã³ãŒããæ¬äœããSyncBlockIndexãªããžã§ã¯ãã®ããããŒã«ã³ããŒããŸãã 以äžã§ãã
éèŠãªåã«å¯ŸããGetHashCodeã®ä»çµã¿
ããã§ãGetHashCodeã¡ãœãããéèŠãªåã«å¯ŸããŠã©ã®ããã«æ©èœãããã«ã€ããŠè©±ããŸãããã åãã£ãŠèšã£ãŠãããŸãããããã¯éåžžã«èå³æ·±ããã®ã§ãã
æåã«èšãããšã¯ãCLRã®äœæè ã¯ããŠãŒã¶ãŒã¿ã€ãã«å¯ŸããŠãã®ã¡ââãœãããåžžã«åå®çŸ©ããããšããå§ãããŸãã
å®éãCLRã«ã¯ãéèŠãªåã«å¯ŸããGetHashCodeã¡ãœããã®å®è£ ã®2ã€ã®ããŒãžã§ã³ãããã䜿çšãããããŒãžã§ã³ã¯å®å šã«åèªäœã«äŸåããŸãã
æåã®ããŒãžã§ã³ïŒ
æ§é ã«åç §ãã£ãŒã«ãããªãããã£ãŒã«ãéã«ç©ºãã¹ããŒã¹ããªãå ŽåãGetHashCodeã¡ãœããã®é«éããŒãžã§ã³ã䜿çšãããŸãã CLRã¯åãªãxorã§ã-æ§é äœã®4ãã€ãããšã«å¿çããŸãã æ§é ã®å å®¹å šäœãé¢ä¿ãããããããã¯é©åãªããã·ã¥ã§ãã ããšãã°ãboolåãšintåã®ãã£ãŒã«ããæã€æ§é äœã«ã¯ã3ãã€ãã®ç©ºãé åããããŸããããã¯ãJITããã£ãŒã«ããé 眮ãããšãã«ã4ãã€ãã§æŽåãããããããã·ã¥ã³ãŒããååŸããããã«2çªç®ã®ããŒãžã§ã³ã䜿çšãããããã§ãã
ã¡ãªã¿ã«ããã®ããŒãžã§ã³ã®å®è£ ã§ã¯ã.NET 4ã§ã®ã¿ä¿®æ£ããããã°ããããŸãããããã¯ãdecimalåã®ããã·ã¥ã³ãŒããæ£ããèšç®ãããªãã£ããšããäºå®ããæããŸããã
ã³ãŒããæ€èšãã
decimal d1 = 10.0m; decimal d2 = 10.00000000000000000m;
æ°å€ã«é¢ããŠã¯ãd1ãšd2ã¯åãã§ããããããè¡šçŸã¯ç°ãªããŸãïŒ10é²è¡šçŸã®æ§è³ªã®ããïŒã ãŸããCLR xorã¯4ãã€ãããšã«umã§ããããïŒ10é²æ°ã¯16ãã€ãã§ãããã4ãã€ãã®ã¿ã§ãïŒãç°ãªãããã·ã¥ã³ãŒããååŸãããŸãã ã¡ãªã¿ã«ããã®ãã°ã¯10é²æ°ã ãã§ãªãããã®ã¿ã€ããå«ããã¹ãŠã®æ§é ã§ãçŸããé«éããŒãžã§ã³ã䜿çšããŠããã·ã¥ã³ãŒããèšç®ããŸãã
2çªç®ã®ããŒãžã§ã³ïŒ
æ§é äœã«åç §ãã£ãŒã«ããå«ãŸããŠãããããã£ãŒã«ãéã«ç©ºãã¹ããŒã¹ãããå Žåãã¡ãœããã®äœéããŒãžã§ã³ã䜿çšãããŸãã CLRã¯ãæ§é ã®æåã®ãã£ãŒã«ããéžæããããã«åºã¥ããŠããã·ã¥ã³ãŒããäœæããŸãã å¯èœãªå Žåããã®ãã£ãŒã«ãã¯äžå€ã§ããå¿ èŠããããŸããããšãã°ãæåååã§ããããã§ãªãå Žåãå€æŽããããšããã·ã¥ã³ãŒããå€æŽãããããŒãšããŠäœ¿çšãããå Žåãããã·ã¥ããŒãã«ã§æ§é ãèŠã€ããããšãã§ããªããªããŸãã æ§é äœã®æåã®ãã£ãŒã«ããå¯å€ã§ããå Žåãããã«ããGetHashCodeã¡ãœããã®æšæºããžãã¯ãç Žå£ãããããšãããããŸãã ããã¯ãæ§é ãå¯å€ã§ãã£ãŠã¯ãªããªããã1ã€ã®çç±ã§ãã ãã®ãã£ãŒã«ãã®åãžã®ãã€ã³ã¿ãŒïŒMethodTablePointerïŒãæã€ãã®ãã£ãŒã«ãã®CLR xor-itããã·ã¥ã³ãŒãã CLRã¯éçãã£ãŒã«ããèæ ®ããŸãããéçãã£ãŒã«ãã¯åãåã®ãã£ãŒã«ãã«ãªãå¯èœæ§ãããããã®çµæãç¡éååž°ã«é¥ãããã§ãã
CLRéçºè
ã¯ãValueTypeã®GetHashCodeã¡ãœããã«ã€ããŠã³ã¡ã³ãããŸãã
/*=================================GetHashCode================================== ** Action: Our algorithm for returning the hashcode is a little bit complex. We look ** for the first non-static field and get it's hashcode. If the type has no ** non-static fields, we return the hashcode of the type. We can't take the ** hashcode of a static member because if that member is of the same type as ** the original type, we'll end up in an infinite loop. **Returns: The hashcode for the type. **Arguments: None. **Exceptions: None. ==============================================================================*/ [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern override int GetHashCode(); // Note that for correctness, we can't use any field of the value type // since that field may be mutable in some way. If we use that field // and the value changes, we may not be able to look up that type in a // hash table. For correctness, we need to use something unique to // the type of this object. // HOWEVER, we decided that the perf of returning a constant value (such as // the hash code for the type) would be too big of a perf hit. We're willing // to deal with less than perfect results, and people should still be // encouraged to override GetHashCode.
ã泚æ
æ§é äœã«ã¯ãç¬èªã®ã¿ã€ãã®ã€ã³ã¹ã¿ã³ã¹ãã£ãŒã«ããå«ããããšã¯ã§ããŸããã ã€ãŸãã次ã®ã³ãŒãã¯ã³ã³ãã€ã«ãããŸããã
public struct Node { int data; Node node; }
ããã¯ãæ§é äœããã«å€ãåãããšãã§ããªããšããäºå®ã«ãããã®ã§ãã 次ã®ã³ãŒãã¯ããããäžå¯èœã§ããããšã確èªããŠããŸãã
var myNode = new Node(); myNode.node.node.node.node.node.node.node.node.node.......
ãã ããç¬èªã®åã®éçãã£ãŒã«ãã¯ããã®æ§é äœã®åã®åäžã®ã€ã³ã¹ã¿ã³ã¹ã«æ ŒçŽãããããããŸã£ããåãå ¥ããããŸãã ã€ãŸãã次ã®ã³ãŒãã¯å®å šã«æå¹ã§ãã
public struct Node { int data; static Node node; }
ã泚æ
ç¶æ³ãããããç解ããã«ã¯ã次ã®ã³ãŒããæ€èšããŠãã ããã
var k1 = new KeyValuePair<int, int>(10, 29); var k2 = new KeyValuePair<int, int>(10, 31); Console.WriteLine("k1 - {0}, k2 - {1}", k1.GetHashCode(), k2.GetHashCode()); var v1 = new KeyValuePair<int, string>(10, "abc"); var v2 = new KeyValuePair<int, string>(10, "def"); Console.WriteLine("v1 - {0}, v2 - {1}", v1.GetHashCode(), v2.GetHashCode());
åè ã®å Žåãæ§é äœã«ã¯åç §ãã£ãŒã«ãããªãããã£ãŒã«ãéã®ç©ºãè·é¢ã¯ãããŸãããintãã£ãŒã«ãã¯4ãã€ãããããããããã·ã¥ã³ãŒãã®èšç®ã«ã¯é«éããŒãžã§ã³ã䜿çšãããã³ã³ãœãŒã«ã«è¡šç€ºãããŸãã
k1-411217769ãk2-411217771
2çªç®ã®ã±ãŒã¹ã§ã¯ãæ§é ã«åç §ãã£ãŒã«ãïŒæååïŒããããããäœéããŒãžã§ã³ã䜿çšãããŸãã CLRã¯intåã®ãã£ãŒã«ããããã·ã¥ã³ãŒããçæããããã®ãã£ãŒã«ããšããŠéžæããæååãã£ãŒã«ãã¯åã«ç¡èŠãããŸãããã®çµæã以äžãã³ã³ãœãŒã«ã«åºåãããŸãïŒ
v1-411217780ãv2-411217780
CLRéçºè ãããŠãŒã¶ãŒã«ãšã£ãŠéèŠãªãã¹ãŠã®ããŒã¿åïŒããã³éèŠãªã ãã§ãªãããã¹ãŠïŒãGetHashCodeã¡ãœãããåå®çŸ©ãããšèšãçç±ã¯æããã ãšæããŸãã æåã«ãäŸã®2çªç®ã®ã±ãŒã¹ã®ããã«ãç°ãªããªããžã§ã¯ãã®ããã·ã¥ã³ãŒããçããçç±ã誀解ããªãããã«ãéåžžã«é«éã«åäœããªãå ŽåããããŸãã
GetHashCodeã¡ãœããããªãŒããŒã©ã€ãããªãå Žåãããã·ã¥ããŒãã«ã®ããŒãšããŠéèŠãªã¿ã€ãã䜿çšããããšã§ãããã©ãŒãã³ã¹ã«å€§ããªææãäžããããšãã§ããŸãã
GetHashCodeã¯æåååã§ã©ã®ããã«æ©èœããŸããïŒ
Stringã¯ã©ã¹ã¯ãGetHashCodeã¡ãœããããªãŒããŒã©ã€ãããŸãã .NET 4.5ã§ã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
GetHashCode X64
public override unsafe int GetHashCode() { if (HashHelpers.s_UseRandomizedStringHashing) return string.InternalMarvin32HashString(this, this.Length, 0L); fixed (char* chPtr1 = this) { int num1 = 5381; int num2 = num1; char* chPtr2 = chPtr1; int num3; while ((num3 = (int) *chPtr2) != 0) { num1 = (num1 << 5) + num1 ^ num3; int num4 = (int) chPtr2[1]; if (num4 != 0) { num2 = (num2 << 5) + num2 ^ num4; chPtr2 += 2; } else break; } return num1 + num2 * 1566083941; } }
ããã¯64ããããã·ã³çšã®ã³ãŒãã§ããããã£ã¬ã¯ãã£ãä»ãã®äžè¬çãªã³ãŒããèŠããš
Gethashcode
public int GetHashCode() { #if FEATURE_RANDOMIZED_STRING_HASHING if(HashHelpers.s_UseRandomizedStringHashing) { return InternalMarvin32HashString(this, this.Length, 0); } #endif // FEATURE_RANDOMIZED_STRING_HASHING unsafe { fixed (char* src = this) { #if WIN32 int hash1 = (5381<<16) + 5381; #else int hash1 = 5381; #endif int hash2 = hash1; #if WIN32 // 32 bit machines. int* pint = (int *)src; int len = this.Length; while (len > 2) { hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0]; hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1]; pint += 2; len -= 4; } if (len > 0) { hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0]; } #else int c; char* s = src; while ((c = s[0]) != 0) { hash1 = ((hash1 << 5) + hash1) ^ c; c = s[1]; if (c == 0) break; hash2 = ((hash2 << 5) + hash2) ^ c; s += 2; } #endif return hash1 + (hash2 * 1566083941); } } }
次ã«ã32ããããŸãã¯64ãããã®ãã·ã³ã«ãã£ãŠéããããããšã«æ³šæããŠãã ããã
ãã®ã¡ãœããã®å®è£ ã¯ã.NETã®åºåããšã«å€ãããšèšãå¿ èŠããããŸãã ããã¯Eric Lippertã«ãã£ãŠæžãããŸããã 圌ã¯ã.NETã®æ¬¡ã®ãªãªãŒã¹ã§å®è£ ãå€æŽããå¯èœæ§ãé«ããããæšæºãã¹ã«ãã£ãŠçæãããããã·ã¥ãããŒã¿ããŒã¹ãŸãã¯ãã£ã¹ã¯ã«æ ŒçŽããªãããšãèŠåããŸããã ãã®ããã.NETã®æåŸã®4ã€ã®ãªãªãŒã¹å šäœã§ãããèµ·ãããŸããã
æåååã«ããã·ã¥ãå®è£ ããŠããçµæããã£ãã·ã¥ãããããã§ã¯ãããŸããã ã€ãŸããGetHashCodeã¡ãœãããåŒã³åºããã³ã«ãæååã®ããã·ã¥ã³ãŒããåèšç®ããŸãã Eric Lippertã«ãããšãããã¯ã¡ã¢ãªãç¯çŽããããã«è¡ãããåæåååãªããžã§ã¯ãã«4ãã€ããè¿œå ããŠã䟡å€ã¯ãããŸããã å®è£ ãéåžžã«é«éã§ããããšãèãããšãããã¯æ£ãããœãªã¥ãŒã·ã§ã³ã ãšæããŸãã
æ°ã¥ããå ŽåãGetHashCodeã¡ãœããã®å®è£ ã§ã¯ã以åã¯ååšããªãã£ãã³ãŒãã衚瀺ãããŸãã
if (HashHelpers.s_UseRandomizedStringHashing) return string.InternalMarvin32HashString(this, this.Length, 0L);
.NET 4.5ã«ã¯ãåãã¡ã€ã³ã®æååã®ããã·ã¥ã³ãŒããèšç®ããæ©èœãããããšãããããŸããã ãããã£ãŠãå±æ§å€ã1ã«èšå®ãããšãã¡ãœãããåŒã³åºããããã¡ã€ã³ã«åºã¥ããŠããã·ã¥ã³ãŒããèšç®ããããšãã§ããŸãã ãããã£ãŠãç°ãªããã¡ã€ã³ã®åãæååã¯ç°ãªãããã·ã¥ã³ãŒããæã¡ãŸãã ãã®ããã·ã¥ã³ãŒããçæããã¡ãœããã¯ç§å¯ã§ããããã®å®è£ ã¯å ¬éãããŠããŸããã
ããªã²ãŒãgethashcodeã®ä»çµã¿
ããªã²ãŒãçšã®GetHashCodeã¡ãœããã®å®è£ ã®èª¬æã«ç§»ãåã«ãããªã²ãŒãã®å®è£ æ¹æ³ã«ã€ããŠèª¬æããŸãã
åããªã²ãŒãã¯MulticastDelegateã¯ã©ã¹ããç¶æ¿ããMulticastDelegateã¯ã©ã¹ã¯Delegateã¯ã©ã¹ããç¶æ¿ããŸãã 1ã€ã®ã¯ã©ã¹MulticastDelegateã§ã§ããããããã®éå±€ã¯æŽå²çã«çºå±ããŠããŸããã
Delegateã¯ã©ã¹ã®GetHashCodeã¡ãœããã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸã
public override int GetHashCode() { return this.GetType().GetHashCode(); }
ã€ãŸããããªã²ãŒãåã®ããã·ã¥ãå®éã«è¿ãããŸãã åŒã³åºãã®ããã®ç°ãªãã¡ãœãããå«ãåãã¿ã€ãã®ããªã²ãŒãã¯ãåžžã«åãããã·ã¥ã³ãŒããè¿ãããšãããããŸãã
ãåç¥ã®ããã«ãããªã²ãŒãã«ã¯ã¡ãœããã®ãã§ãŒã³ãå«ããããšãã§ããŸããã€ãŸãã1ã€ã®ããªã²ãŒããåŒã³åºããšè€æ°ã®ã¡ãœãããåŒã³åºãããŸãããã®å Žåãã¡ãœããã®æ°ã«é¢ä¿ãªãåãã¿ã€ãã®ããªã²ãŒãã¯1ã€ã®ããã·ã¥ã³ãŒããæã€ããããã®å®è£ ã¯é©åã§ã¯ãããŸããããããã£ãŠãMulticastDelegateã§ã¯ãããªã²ãŒãã®åºç€ãšãªãåã¡ãœãããé¢äžããããã«GetHashCodeã¡ãœãããåå®çŸ©ãããŸãã ãã ããã¡ãœããã®æ°ãšããªã²ãŒãã®çš®é¡ãåãå Žåãããã·ã¥ã³ãŒãã¯åãã«ãªããŸãã
MulticastDelegateã¯ã©ã¹ã®ã¡ãœããã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸã
public override sealed int GetHashCode() { if (this.IsUnmanagedFunctionPtr()) return ValueType.GetHashCodeOfPtr(this._methodPtr) ^ ValueType.GetHashCodeOfPtr(this._methodPtrAux); object[] objArray = this._invocationList as object[]; if (objArray == null) return base.GetHashCode(); int num = 0; for (int index = 0; index < (int) this._invocationCount; ++index) num = num * 33 + objArray[index].GetHashCode(); return num; }
ãåç¥ã®ããã«ãããªã²ãŒãã¯ãã¡ãœãããè€æ°ããå Žåã«ã®ã¿ãã¡ãœããã_invocationListãªã¹ãã«ä¿åããŸãã
ããªã²ãŒãã«å«ãŸããã¡ãœããã1ã€ã ãã®å Žåãäžèšã®ã³ãŒãã§ã¯objArray = nullã§ãããããã«å¿ããŠãããªã²ãŒãã®ããã·ã¥ã³ãŒãã¯ããªã²ãŒãã¿ã€ãã®ããã·ã¥ã³ãŒããšçãããªããŸãã
object[] objArray = this._invocationList as object[]; if (objArray == null) return base.GetHashCode();
ç¶æ³ãæ確ã«ããããã«ã次ã®ã³ãŒããæ€èšããŠãã ãã
Func<int> f1 = () => 1; Func<int> f2 = () => 2;
ãããã®ããªã²ãŒãã®ããã·ã¥ã³ãŒãã¯ãFunc <int>åã®ããã·ã¥ã³ãŒããšåãã§ããã€ãŸããäºãã«çããã§ãã
Func<int> f1 = () => 1; Func<int> f2 = () => 2; f1 += () => 3; f2 += () => 4;
ãã®å Žåãã¡ãœããã¯ç°ãªããŸãããããªã²ãŒãã®ããã·ã¥ã³ãŒããäžèŽããŸãã ãã®å Žåã次ã®ã³ãŒãã䜿çšããŠããã·ã¥ã³ãŒããèšç®ããŸãã
int num = 0; for (int index = 0; index < (int) this._invocationCount; ++index) num = num * 33 + objArray[index].GetHashCode(); return num;
ãããŠæåŸã®ã±ãŒã¹
Func<int> f1 = () => 1; Func<int> f2 = () => 2; f1 += () => 3; f1 += () => 5; f2 += () => 4;
ãããã®ããªã²ãŒãã®ã¡ãœããã®æ°ãçãããªããããããã·ã¥ã³ãŒãã¯ç°ãªããŸãïŒåã¡ãœããã¯çµæã®ããã·ã¥ã³ãŒãã«åœ±é¿ããŸãïŒã
å¿ååã«å¯ŸããGetHashCodeã®ä»çµã¿
ãåãã®ããã«ãå¿ååã¯CïŒ3.0ã®æ°æ©èœã§ãã ããã«ãããã¯CLRããããã«ã€ããŠäœãç¥ããªããããããããæ§æç³ãšåŒã°ããèšèªã®æ©èœã§ãã
GetHashCodeã¡ãœããã¯ãåãã£ãŒã«ãã䜿çšããããã«åå®çŸ©ãããŸãã ãã®ãããªå®è£ ã䜿çšãããšã2ã€ã®å¿ååã¯ããã¹ãŠã®ãã£ãŒã«ããçããå Žåã«ã®ã¿åãããã·ã¥ã³ãŒããè¿ããŸãã ãã®å®è£ ã«ãããå¿ååã¯ããã·ã¥ããŒãã«ã®ããŒã«é©ãããã®ã«ãªããŸãã
var newType = new { Name = "Timur", Age = 20, IsMale = true };
ãã®ãããªå¿ååã®å Žåã次ã®ã³ãŒããçæãããŸãã
public override int GetHashCode() { return -1521134295 * (-1521134295 * (-1521134295 * -974875401 + EqualityComparer<string>.Default.GetHashCode(this.Name)) + EqualityComparer<int >.Default.GetHashCode(this.Age)) + EqualityComparer<bool>.Default.GetHashCode(this.IsMale); }
ã泚æ
GetHashCodeã¡ãœãããEqualsã¡ãœããã«ãã£ãŠãªãŒããŒã©ã€ããããŠããå Žåãããã«å¿ããŠãªãŒããŒã©ã€ãããå¿ èŠããããŸãã
var newType = new { Name = "Timur", Age = 20, IsMale = true }; var newType1 = new { Name = "Timur", Age = 20, IsMale = true }; if (newType.Equals(newType1)) Console.WriteLine("method Equals return true"); else Console.WriteLine("method Equals return false"); if (newType == newType1) Console.WriteLine("operator == return true"); else Console.WriteLine("operator == return false");
以äžãã³ã³ãœãŒã«ã«è¡šç€ºãããŸãã
ã¡ãœããEqualsã¯trueãè¿ããŸã
æŒç®å== falseãè¿ããŸã
å¿ååã¯ãValueTypeã§è¡ã£ãããã«ïŒãªãã¬ã¯ã·ã§ã³ãªãã§ã®ã¿ïŒãã¹ãŠã®ãã£ãŒã«ãããã§ãã¯ããããã«Equalsã¡ãœãããåå®çŸ©ããŸãããçå€æŒç®åã¯åå®çŸ©ããŸããã ãããã£ãŠãEqualsã¡ãœããã¯å€ã§æ¯èŒããç䟡æŒç®åã¯åç §ã§æ¯èŒããŸãã
Equalsã¡ãœãããšGetHashCodeã¡ãœããããªãŒããŒã©ã€ãããå¿ èŠãããã®ã¯ãªãã§ããïŒ
å¿ååã¯LINQã§ã®äœæ¥ãç°¡çŽ åããããã«äœæããããããçãã¯æ確ã«ãªããŸãã å¿ååã¯ãLINQã®ã°ã«ãŒãããã³çµåæäœã§ããã·ã¥ããŒãšããŠäŸ¿å©ã«äœ¿çšãããŸãã
ã泚æ
ãããã«
ã芧ã®ãšãããããã·ã¥ã³ãŒãã®çæã¯åçŽãªåé¡ã§ã¯ãããŸããã è¯ãããã·ã¥ãçæããã«ã¯ãå€ãã®åªåãããå¿ èŠããããCLRéçºè ã¯ç§ãã¡ã®ç掻ã楜ã«ããããã«å€ãã®è²æ©ãããªããã°ãªããŸããã§ããã ããã·ã¥ã³ãŒããçæããããšã¯è¯ãããšã§ãããã¹ãŠã®å Žåã«ãããŠäžå¯èœã§ãããããã£ãŠãã«ã¹ã¿ã ã¿ã€ãã®GetHashCodeã¡ãœããããªãŒããŒã©ã€ãããŠãç¹å®ã®ç¶æ³ã«åãããŠèª¿æŽããããšããå§ãããŸãã
èªãã§ãããŠããããšãïŒ ãã®èšäºãã圹ã«ç«ãŠã°å¹žãã§ãã
èšäºã®æŽæ°ãããåçã芪åã«æäŸããŠãããDreamWalkerã®ãŠãŒã¶ãŒã«æè¬ããŸãã