我很好奇,因为我猜它会对性能有影响。它会考虑整个字符串吗?如果是的话,它在处理长字符串时会很慢。如果它只考虑字符串的一部分,它的性能会很差(例如,如果它只考虑字符串的开头,如果HashSet包含的大多数字符串具有相同的字符串,它的性能会很差)。
HashSet
wgx48brx1#
当你有这样的问题时,一定要获得Reference Source源代码。它比你从反编译器中看到的要多得多。选择一个与你喜欢的.NET目标匹配的源代码,这个方法在不同版本之间有很大的变化。我在这里只复制它的.NET 4.5版本。从源代码.NET 4.5\4.6.0.0\net\clr\src\BCL\System\String.cs\604718\String.cs中检索
public override 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) { Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'"); Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary"); #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 #if DEBUG // We want to ensure we can change our hash function daily. // This is perfectly fine as long as you don't persist the // value from GetHashCode to disk or count on String A // hashing before string B. Those are bugs in your code. hash1 ^= ThisAssembly.DailyBuildNumber; #endif return hash1 + (hash2 * 1566083941); } } }
这可能超出了您的预期,我将对代码进行一些注解:
tez616oj2#
检查源代码(ILSpy提供),我们可以看到它确实遍历了字符串的长度。
// string [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), SecuritySafeCritical] public unsafe override int GetHashCode() { IntPtr arg_0F_0; IntPtr expr_06 = arg_0F_0 = this; if (expr_06 != 0) { arg_0F_0 = (IntPtr)((int)expr_06 + RuntimeHelpers.OffsetToStringData); } char* ptr = arg_0F_0; int num = 352654597; int num2 = num; int* ptr2 = (int*)ptr; for (int i = this.Length; i > 0; i -= 4) { num = ((num << 5) + num + (num >> 27) ^ *ptr2); if (i <= 2) { break; } num2 = ((num2 << 5) + num2 + (num2 >> 27) ^ ptr2[(IntPtr)4 / 4]); ptr2 += (IntPtr)8 / 4; } return num + num2 * 1566083941; }
2条答案
按热度按时间wgx48brx1#
当你有这样的问题时,一定要获得Reference Source源代码。它比你从反编译器中看到的要多得多。选择一个与你喜欢的.NET目标匹配的源代码,这个方法在不同版本之间有很大的变化。我在这里只复制它的.NET 4.5版本。从源代码.NET 4.5\4.6.0.0\net\clr\src\BCL\System\String.cs\604718\String.cs中检索
这可能超出了您的预期,我将对代码进行一些注解:
tez616oj2#
检查源代码(ILSpy提供),我们可以看到它确实遍历了字符串的长度。