Runtime: ํ•ด์‹œ ์ฝ”๋“œ ๊ฒฐํ•ฉ์— ๋„์›€์ด ๋˜๋„๋ก HashCode ์œ ํ˜• ์ถ”๊ฐ€

์— ๋งŒ๋“  2016๋…„ 04์›” 25์ผ  ยท  206์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: dotnet/runtime

๊ธด ํ† ๋ก ์„ 200๊ฐœ ์ด์ƒ์˜ ๋Œ“๊ธ€๋กœ ๋Œ€์ฒดํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฌธ์ œ dotnet/corefx#14354

์ด ๋ฌธ์ œ๋Š” ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค !!!


๋™๊ธฐ ๋ถ€์—ฌ

Java์—๋Š” ๊ตฌ์„ฑ ํ•„๋“œ์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฒฐํ•ฉํ•˜์—ฌ Object.hashCode() ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ Objects.hash ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถˆํ–‰ํ•˜๊ฒŒ๋„, .NET์€ ๊ทธ๋Ÿฌํ•œ ํ•ด๋‹น์ด ์—†์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž์ฒ˜๋Ÿผ ์ž์‹ ์˜ ํ•ด์‹œ๋ฅผ ๋กค ๊ฐ•์ œ๋กœ ์ด :

public override int GetHashCode()
{
    unchecked
    {
        int result = 17;
        result = result * 23 + field1.GetHashCode();
        result = result * 23 + field2.GetHashCode();
        return result;
    }
}

๋•Œ๋•Œ๋กœ ์‚ฌ๋žŒ๋“ค์€ ์ด๋ฅผ ์œ„ํ•ด Tuple.Create(field1, field2, ...).GetHashCode() ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— (๋ถ„๋ช…ํžˆ) ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ œ์•ˆ

  • ํ˜„์žฌ ์ œ์•ˆ์„œ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ๋ชฉ๋ก(๋งˆ์ง€๋ง‰ ์Šน์ธ ๋ฒ„์ „ https://github.com/dotnet/corefx/issues/8034#issuecomment-262331783):

    • Empty ์†์„ฑ ์ถ”๊ฐ€( ImmutableArray ์œ ์‚ฌํ•œ ์ž์—ฐ์Šค๋Ÿฌ์šด ์‹œ์ž‘์ )

    • ์ธ์ˆ˜ ์ด๋ฆ„ ์—…๋ฐ์ดํŠธ๋จ: hash -> hashCode , obj -> item

namespace System
{
    public struct HashCode : IEquatable<HashCode>
    {
        public HashCode();

        public static HashCode Empty { get; }

        public static HashCode Create(int hashCode);
        public static HashCode Create<T>(T item);
        public static HashCode Create<T>(T item, IEqualityComparer<T> comparer);

        public HashCode Combine(int hashCode);
        public HashCode Combine<T>(T item);
        public HashCode Combine<T>(T item, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCode hashCode);

        public static bool operator ==(HashCode left, HashCode right);
        public static bool operator !=(HashCode left, HashCode right);

        public bool Equals(HashCode other);
        public override bool Equals(object obj);
        public override int GetHashCode();
        public override string ToString();
    }
}

์šฉ๋ฒ•:

```c#
int hashCode1 = HashCode.Create(f1).Combine(f2).Value;
int hashCode2 = hashes.Aggregate(HashCode.Empty, (์‹œ๋“œ, ํ•ด์‹œ) => seed.Combine(ํ•ด์‹œ));

var hashCode3 = HashCode.Empty;
foreach(ํ•ด์‹œ์—์„œ int ํ•ด์‹œ) { hashCode3 = hashCode3.Combine(hash); }
(int)ํ•ด์‹œ์ฝ”๋“œ3;
```

๋…ธํŠธ

๊ตฌํ˜„์€ HashHelpers ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Design Discussion api-needs-work area-System.Numerics

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

[@redknightlois] ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ด System ํ•˜๋Š” ์ด์œ ๋ผ๋ฉด ์ •๋‹นํ™”๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” object.GetHashCode() ๊ตฌํ˜„์„ ๋•๊ธฐ ์œ„ํ•ด HashCode ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

์ €์™€ @KrzysztofCwalina ๋„ ์‚ฌ์šฉํ•œ ๊ทผ๊ฑฐ์˜€์Šต๋‹ˆ๋‹ค. ํŒ๋งค ๋œ!

๋ชจ๋“  206 ๋Œ“๊ธ€

๋น ๋ฅด๊ณ  ๋”๋Ÿฌ์šด ๊ฒƒ์„ ์›ํ•˜๋ฉด ValueTuple.Create(field1, field2).GetHashCode() ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Tuple ์—์„œ ์‚ฌ์šฉ๋œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฉฐ(์ด ์ ์— ์žˆ์–ด์„œ๋Š” Objects ์—์„œ์™€ ์œ ์‚ฌํ•จ) ํ• ๋‹น ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์–ผ๋งˆ๋‚˜ ์ข‹์€ ํ•ด์‹œ๊ฐ€ ํ•„์š”ํ•œ์ง€, ํ•„๋“œ ๊ฐ’์ด ์–ด๋–ค ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€(์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ข‹์€ ๊ฒฐ๊ณผ ๋˜๋Š” ๋‚˜์œ ๊ฒฐ๊ณผ๋ฅผ ์ค„ ๊ฒƒ์ธ์ง€์— ์˜ํ–ฅ์„ ๋ฏธ์นจ), hashDoS ๊ณต๊ฒฉ์˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€, ๋ชจ๋“ˆ๋กœ ์ถฉ๋Œ์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง์ˆ˜ ํ•ด์‰ฌ(์ด์ง„ ์ง์ˆ˜ ํ•ด์‹œ ํ…Œ์ด๋ธ”์—์„œ์™€ ๊ฐ™์ด) ๋“ฑ์œผ๋กœ ์ธํ•ด ๋งŒ๋Šฅ์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@JonHanna ๋‚˜๋Š” ๊ทธ ์งˆ๋ฌธ์ด ์˜ˆ๋ฅผ ๋“ค์–ด string.GetHashCode() ์—๋„ ์ ์šฉ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Hash ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ณด๋‹ค ๋” ์–ด๋ ค์šด ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ํŠน๋ณ„ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž๋Š” Hash ์‚ฌ์šฉ์„ ์‰ฝ๊ฒŒ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ์ง€๋งŒ string.GetHashCode() ์‚ฌ์šฉ์„ ์ค‘๋‹จํ•˜๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ๋” ๊ฐ„๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋น ๋ฅด๊ณ  ๋”๋Ÿฌ์šด ๊ฒƒ์„ ์›ํ•˜๋ฉด ValueTuple.Create(field1, field2).GetHashCode()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„, ์ข‹์€ ์ƒ๊ฐ์ด๊ตฐ์š”. ์ด ๊ธ€์„ ์ž‘์„ฑํ•  ๋•Œ ValueTuple ์ƒ๊ฐํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด C# 7/๋‹ค์Œ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฆด๋ฆฌ์Šค๊นŒ์ง€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ๊ทธ๊ฒƒ์ด ๊ทธ ์„ฑ๋Šฅ์ด ๋  ๊ฒƒ์ธ์ง€์กฐ์ฐจ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค( EqualityComparer ์†์„ฑ/๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์€ ํ•ฉ์‚ฐ๋  ์ˆ˜ ์žˆ์Œ). ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์ด๊ฒƒ์„ ์ธก์ •ํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ค ๋ฒค์น˜๋งˆํฌ๋„ ์ทจํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ์ •๋ง๋กœ ์•Œ์ง€ ๋ชปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ๋žŒ๋“ค์ด ํŠœํ”Œ์„ ํ•ดํ‚น ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด์‹ฑ ์ „์šฉ/๋‹จ์ˆœ ํด๋ž˜์Šค๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์–ผ๋งˆ๋‚˜ ์ข‹์€ ํ•ด์‹œ๊ฐ€ ํ•„์š”ํ•œ์ง€, ํ•„๋“œ ๊ฐ’์ด ์–ด๋–ค ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€(์–ด๋–ค ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ข‹์€ ๊ฒฐ๊ณผ ๋˜๋Š” ๋‚˜์œ ๊ฒฐ๊ณผ๋ฅผ ์ค„ ๊ฒƒ์ธ์ง€์— ์˜ํ–ฅ์„ ๋ฏธ์นจ), hashDoS ๊ณต๊ฒฉ์˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€, ๋ชจ๋“ˆ๋กœ ์ถฉ๋Œ์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง์ˆ˜ ํ•ด์‰ฌ(์ด์ง„ ์ง์ˆ˜ ํ•ด์‹œ ํ…Œ์ด๋ธ”์—์„œ์™€ ๊ฐ™์ด) ๋“ฑ์œผ๋กœ ์ธํ•ด ๋งŒ๋Šฅ์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ ˆ๋Œ€์ ์œผ๋กœ ๋™์˜ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๊ตฌํ˜„์ด ์ด๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ArraySegment ์˜ ํ˜„์žฌ ๊ตฌํ˜„ ์€ ๋งค์šฐ ์ˆœ์ง„ํ•ฉ๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์˜ ์ฃผ์š” ๋ชฉ์ ์€ (ํ• ๋‹น์„ ํ”ผํ•˜๋Š” ๊ฒƒ๊ณผ ํ•จ๊ป˜) ํ•ด์‹ฑ์— ๋Œ€ํ•ด ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค ์ด ์ด์™€ ๊ฐ™์€ ์–ด๋ฆฌ์„์€ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด go-to ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜๊ฐ€ ์„ค๋ช…ํ•œ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์€ ์ž์‹ ์˜ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„ C# 7/๋‹ค์Œ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฆด๋ฆฌ์Šค๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ œ๊ณต ์ง€์›์ด ์•„๋‹Œ C# 2์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋˜๋Š” ์„ฑ๋Šฅ์ด ์ข‹์€์ง€ ์•Œ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(EqualityComparer์— ๋Œ€ํ•œ ์†์„ฑ/๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ํ•ฉ์‚ฐ๋  ์ˆ˜ ์žˆ์Œ)

์ด ์ˆ˜์—…์€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅผ๊นŒ์š”? obj == null ? 0 : obj.GetHashCode() ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ๋” ๋น ๋ฅด๋ฉด ๊ทธ๋ณด๋‹ค ๋” ๋นจ๋ฆฌ ValueTuple ๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ช‡ ์ฃผ ์ „์— ์ด ์ œ์•ˆ์„ +1ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์—ˆ์ง€๋งŒ ValueTuple ๋ฅผ ์œ„ํ•ด Tuple ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŠธ๋ฆญ์˜ ํ• ๋‹น ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์— ๋น„์ถ”์–ด ๋œ ์˜ํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ๋‘ ๊ฐœ์˜ ์˜์ž ์‚ฌ์ด์—์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํŠน๋ณ„ํžˆ ์ „๋ฌธํ™” ๋œ ๊ฒƒ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ValueTuple ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ์ด์ƒ์˜ ๊ฒƒ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ด์™€ ๊ฐ™์€ ํด๋ž˜์Šค๋Š” ๋ฉ€๋ฆฌ ๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ถฉ๋ถ„ํ•œ.

๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๊ฐ€ C#7์„ ๊ฐ–๊ฒŒ ๋˜๋ฉด ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ๋ฒ•์ ์ธ ์„คํƒ•์„ ๊ฐ–๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@JonHanna

์ด ์ˆ˜์—…์€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅผ๊นŒ์š”? ๋ช…์‹œ์ ์œผ๋กœ obj == null ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ? 0 : obj.GetHashCode()๊ฐ€ ValueTuple๋กœ ์ด๋™ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค.

ValueTuple ์— ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด Hash ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์€ ๋˜ํ•œ ํŒŒ์ผ์˜ LOC๋ฅผ ์ƒ๋‹นํžˆ ๊ฐ์†Œ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค(ํ˜„์žฌ ์•ฝ 2000์ค„ ์ •๋„์ž…๋‹ˆ๋‹ค).

ํŽธ์ง‘ํ•˜๋‹ค:

ํŠน๋ณ„ํžˆ ์ „๋ฌธํ™”๋œ ๊ฒƒ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ValueTuple์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค์ด์ง€๋งŒ ๋ฌธ์ œ๋Š” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์„ ๊นจ๋‹ซ์ง€ ๋ชปํ•˜๊ณ  ์ž์‹ ์˜ ์—ด๋“ฑํ•œ ์ˆœ์ง„ํ•œ ํ•ด์‹ฑ ๊ธฐ๋Šฅ(์œ„์— ๋งํฌ๋œ ๊ฒƒ๊ณผ ๊ฐ™์€)์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ •๋ง๋กœ ๋’ค์ฒ˜์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„.

์•„๋งˆ๋„ ์ด ๋ฌธ์ œ์˜ ๋ฒ”์œ„ ๋ฐ–์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ „๋ฌธ๊ฐ€๊ฐ€ ์ž‘์„ฑํ•œ ๊ณ ์„ฑ๋Šฅ ์•”ํ˜ธํ™” ๋ฐ ๋น„์•”ํ˜ธํ™” ํ•ด์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ํ•ด์‹ฑ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด ์—ฌ๊ธฐ์„œ ์Šน๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด xxHash32, xxHash64, Metro128์„ ์ฝ”๋”ฉํ•˜๊ณ  128์—์„œ 64๋กœ, 64์—์„œ 32๋น„ํŠธ๋กœ ๋‹ค์šด์ƒ˜ํ”Œ๋งํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ ํ™”๋œ ํ•จ์ˆ˜์˜ ๋ฐฐ์—ด์„ ๊ฐ–๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ตœ์ ํ™”๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ์ „ํžˆ ํ•„์š”์— ๋”ฐ๋ผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ด€์‹ฌ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๊ตฌํ˜„์„ ๊ธฐ๊บผ์ด ๊ธฐ๋ถ€ํ•˜์—ฌ ์ „๋ฌธ๊ฐ€๊ฐ€ ๊ฒ€ํ† ํ•˜๊ณ  ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@redknightlois ๊ทธ๋Ÿฐ ๋…ธ๋ ฅ์— ๋‚ด SpookyHash ๊ตฌํ˜„์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

@svick string.GetHashCode()์— ์ฃผ์˜ํ•˜์„ธ์š”. ํ•˜์ง€๋งŒ ์ด๋Š” ๋งค์šฐ ๊ตฌ์ฒด์ ์ž…๋‹ˆ๋‹ค. ์•„์ฃผ ์ข‹์€ ์ด์œ ๋Š” Hash DoS ๊ณต๊ฒฉ์ž…๋‹ˆ๋‹ค.

@terrajobst , API ๋ถ„๋ฅ˜/๊ฒ€ํ†  ๋Œ€๊ธฐ์—ด์—์„œ ์ด๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ๋ฉ€๋ฆฌ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๊ฐ€ ํ•ญ์ƒ ํ”Œ๋žซํผ์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์—ˆ๋˜ ๋‹จ์ˆœํ•œ API๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ์‹ค์ œ๋กœ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•œ ์ž„๊ณ„๋Ÿ‰์„ ๊ฐ–๊ฒŒ ๋˜์—ˆ์„๊นŒ์š”?

์ฐธ์กฐ: @ellismg

ํ˜„์žฌ ์ƒํƒœ์—์„œ ๊ฒ€ํ† ํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@mellinoe ๊ต‰์žฅํ•ด ! ๋‚˜๋Š” ์ œ์•ˆ์„ ์ข€ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์•ฝ๊ฐ„ ์ •๋ฆฌํ–ˆ๊ณ  ๋งˆ์ง€๋ง‰์— ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์งˆ๋ฌธ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

@jamesqo long ๊ธฐ๋ฐ˜๋„ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@redknightlois , ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. Combine long ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ํฌํ•จํ•˜๋„๋ก ์ œ์•ˆ์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

@JonHanna ์˜ ์ œ์•ˆ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

C# return ValueTuple.Create(a, b, c).GetHashCode();

๊ทธ๊ฒƒ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ์ถฉ๋ถ„ํ•œ ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ์ง€ ์•Š๋Š” ํ•œ, ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์ด ์ปท์„ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ ๋ช‡ ๋ฐฐ ๋” ๋‚˜๋น ์กŒ๋‹ค๋Š” ๊ฒƒ ์™ธ์— ๋‹ค๋ฅธ ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ์ƒ๊ฐ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด ํŠน์ • ๊ฒฝ์šฐ๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ์ƒˆ ๋Ÿฐํƒ€์ž„์— ์ตœ์ ํ™”๊ฐ€ ์—†๋Š” ํ•œ ์ด ๋ถ„์„์€ ๋ฌด์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ 1.0.1์—์„œ ์ด๊ฒƒ์„ ์‹œ๋„ํ–ˆ๋‹ค๊ณ  ๋งํ•˜๋ฉด์„œ.

์˜ˆ๋ฅผ ๋“ค์–ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

ValueTuple ์— ์‚ฌ์šฉ๋˜๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์™€ ์ƒ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

        internal static class HashHelpers
        {
            public static int Combine(int h1, int h2)
            {
                // The jit optimizes this to use the ROL instruction on x86
                // Related GitHub pull request: dotnet/coreclr#1830
                uint shift5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
                return ((int)shift5 + h1) ^ h2;
            }
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryStaticCall()
        {
            return HashHelpers.Combine(10202, 2003);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryValueTuple()
        {
            return ValueTuple.Create(10202, 2003).GetHashCode();
        }
    }

์ด์ œ ์ตœ์ ํ™” ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐํšŒ๋Š” ์ฐจ์ด๊ฐ€ ์—†์–ด์•ผ ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

ValueTuple ์˜ ์‹ค์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

image
์ด์ œ ์—ฌ๊ธฐ์„œ ๋ฌด์—‡์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋จผ์ € ์Šคํƒ์— ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“  ๋‹ค์Œ ์‹ค์ œ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ Hash.Combine ์˜ ์‹ค์ œ ๊ตฌํ˜„์ด ๋  ์ˆ˜ ์žˆ๋Š” HashHelper.Combine ์˜ ์‚ฌ์šฉ๊ณผ ๋น„๊ตํ•˜์‹ญ์‹œ์˜ค.

image

์•Œ์•„์š”!!!
ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถ”์ง€ ๋ง๊ณ ... ์‹ค์ œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryStaticCall(int h1, int h2)
        {
            return HashHelpers.Combine(h1, h2);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryValueTuple(int h1, int h2)
        {
            return ValueTuple.Create(h1, h2).GetHashCode();
        }

        static unsafe void Main(string[] args)
        {
            var g = new Random();
            int h1 = g.Next();
            int h2 = g.Next(); 
            Console.WriteLine(TryStaticCall(h1, h2));
            Console.WriteLine(TryValueTuple(h1, h2));
        }

image

์ข‹์€ ์ ์€ ๋งค์šฐ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€์•ˆ๊ณผ ๋น„๊ตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

image

์ด์ œ ์„ ์„ ๋„˜์ž...

        internal static class HashHelpers
        {
            public static int Combine(int h1, int h2)
            {
                // The jit optimizes this to use the ROL instruction on x86
                // Related GitHub pull request: dotnet/coreclr#1830
                uint shift5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
                return ((int)shift5 + h1) ^ h2;
            }
            public static int Combine(int h1, int h2, int h3, int h4)
            {
                return Combine(Combine(h1, h2), Combine(h3, h4));
            }
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryStaticCall(int h1, int h2, int h3, int h4)
        {
            return HashHelpers.Combine(h1, h2, h3, h4);
        }

๊ทธ๋ฆฌ๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋Š” ๊ฝค ์˜ˆ์‹œ์ ์ž…๋‹ˆ๋‹ค

image

JIT๊ฐ€ ํ˜ธ์ถœ์— ๋Œ€ํ•ด ์ƒ์„ฑํ•˜๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์‹ค์ œ๋กœ ๊ฒ€์‚ฌํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ํ”„๋กค๋กœ๊ทธ์™€ ์—ํ•„๋กœ๊ทธ๋งŒ ์žˆ์œผ๋ฉด ์ œ์•ˆ์„ ํฌํ•จํ•˜๋Š” ๊ฒƒ์„ ์ •๋‹นํ™”ํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

image

๋ถ„์„์˜ ํ•ต์‹ฌ์€ ๊ฐ„๋‹จ ํ•ฉ๋‹ˆ๋‹ค. ๋ณด์œ  ์œ ํ˜•์ด struct ๋ผ๋Š” ๊ฒƒ์ด ๋ฌด๋ฃŒ๋ผ๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. :)

ํšŒ์˜ ์ค‘์— ์„ฑ๊ณผ๊ฐ€ ๊ฑฐ๋ก ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์ด API๊ฐ€ ํ•ซ ๊ฒฝ๋กœ์— ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ํ•˜์ž๋ฉด, API๊ฐ€ ์—†์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ง์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ตฌ์ฒด์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์—†๋Š” ํ•œ API๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ๋” ์–ด๋ ต๋‹ค๋Š” ๋ง์„ ํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. "X์— ํ•„์š”ํ•˜๋ฏ€๋กœ X๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๊ฐ€ ์„ฑ๊ณต์˜ ์ฒ™๋„"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ƒˆ๋กœ์šด ์ž‘์—…์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ  ๋™์ผํ•œ ์ž‘์—…์„ ๋ณด๋‹ค ์ตœ์ ํ™”๋œ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” API์— ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋น ๋ฅด๊ณ  ์ข‹์€ ํ’ˆ์งˆ์˜ ํ•ด์‹œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ• ์ˆ˜๋ก ๊ฐœ์ฒด์— ์‚ฌ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ํ‘œ์‹œ๋  ๊ฐ’์˜ ๋ฒ”์œ„๋ฅผ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•˜๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ํ•ด์‹œ๊ฐ€ ๋” ๋งŽ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋„์šฐ๋ฏธ์ผ์ˆ˜๋ก ๊ทธ๋Ÿฐ ๋„์šฐ๋ฏธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@terrajobst , ์„ฑ๋Šฅ์ด ์ด ์ œ์•ˆ์˜ ์ฃผ์š” ๋™๊ธฐ์˜€์ง€๋งŒ ์œ ์ผํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ „์šฉ ์œ ํ˜•์ด ์žˆ์œผ๋ฉด ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ์„ฑ์— ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. C# 7์—์„œ ๊ธฐ๋ณธ ์ œ๊ณต ํŠœํ”Œ ์ง€์›์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ๊ฐœ๋ฐœ์ž๋Š” ์ž์‹ ์ด ๊ฐ’์œผ๋กœ ๋™์ผํ•˜๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฐ˜๋“œ์‹œ ์•Œ์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋”๋ผ๋„ ํŠœํ”Œ์ด GetHashCode ์žฌ์ •์˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์žŠ์–ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฒฐ๊ตญ .NET์—์„œ GetHashCode ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ Google์— ์•Œ๋ ค์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ValueTuple.Create.GetHashCode ์‚ฌ์šฉ ์‹œ ๋ฏธ๋ฌ˜ํ•œ ์ •ํ™•์„ฑ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ 8๊ฐœ ์š”์†Œ, ๋งˆ์ง€๋ง‰ 8๊ฐœ ์š”์†Œ๋งŒ ํ•ด์‹œ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.

@terrajobst RavenDB GetHashCode ์„ฑ๋Šฅ์€ ์šฐ๋ฆฌ์˜ ์ˆ˜์ต์— ํฐ ํƒ€๊ฒฉ์„ ์ฃผ์–ด ๊ฒฐ๊ตญ ๊ณ ๋„๋กœ ์ตœ์ ํ™”๋œ ์ „์ฒด ๋ฃจํ‹ด ์„ธํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Roslyn์—๋„ ์ž์ฒด ๋‚ด๋ถ€ ํ•ด์‹ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/InternalUtilities/Hash.cs ๋˜ํ•œ ์—ฌ๊ธฐ์—์„œ Roslyn์— ๋Œ€ํ•œ ํ† ๋ก ์„ ํ™•์ธํ•˜์„ธ์š”. https://github .com/dotnet/coreclr/issues/1619 ... ๋”ฐ๋ผ์„œ ์„ฑ๋Šฅ์ด ํ•ต์‹ฌ์ผ ๋•Œ ์šฐ๋ฆฌ๋Š” ์ œ๊ณต๋œ ํ”Œ๋žซํผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์ž์ฒด์ ์œผ๋กœ ๋กค๋ฐฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋ฐ ๊ฒฐ๊ณผ๋ฅผ ์ง€๋ถˆํ•ด์•ผ ํ•จ).

๋˜ํ•œ @jamesqo ๋ฌธ์ œ๋Š” ์™„์ „ํžˆ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋งŽ์€ ํ•ด์‹œ๋ฅผ ๊ฒฐํ•ฉํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ 1M์˜ ๊ฒฝ์šฐ ํ•ด๋‹น ํ•ด์‹œ๋กœ ์ ˆ๋ฒฝ์„ ๋„˜์–ด์„ค ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

@JonHanna

๋น ๋ฅด๊ณ  ์ข‹์€ ํ’ˆ์งˆ์˜ ํ•ด์‹œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ• ์ˆ˜๋ก ๊ฐœ์ฒด์— ์‚ฌ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ํ‘œ์‹œ๋  ๊ฐ’์˜ ๋ฒ”์œ„๋ฅผ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•˜๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ํ•ด์‹œ๊ฐ€ ๋” ๋งŽ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋„์šฐ๋ฏธ์ผ์ˆ˜๋ก ๊ทธ๋Ÿฐ ๋„์šฐ๋ฏธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ ์ ˆํ•œ ํ•ด์‹œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๋ฅผ ์ž…๋ ฅํ•˜๋„๋ก ๊ถŒ์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„์šฐ๋ฏธ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์ง€ ์•Š๋‹ค๋Š” ๋ง์”€์ด์‹ ๊ฐ€์š”?

์‹ค์ œ๋กœ๋Š” ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ์‚ฌ์‹ค์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. Hash.Combine ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ GetHashCode ๊ตฌํ˜„์„ ๊ฐœ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด์‹ฑ์„ ํ•  ์ค„ ์•„๋Š” ์‚ฌ๋žŒ์€ Hash.Combine ๋ฅผ ํ‰๊ฐ€ํ•˜์—ฌ ์ž์‹ ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋งž๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด์‹ฑ์— ๋Œ€ํ•ด ์ž˜ ๋ชจ๋ฅด๋Š” ์ดˆ๋ณด์ž๋Š” ์ ์ ˆํ•œ ํ•ด์‹œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ์„ฑ ํ•„๋“œ๋ฅผ xor-ing(๋˜๋Š” ๋” ๋‚˜์˜๊ฒŒ๋Š” ์ถ”๊ฐ€)ํ•˜๋Š” ๋Œ€์‹  Hash.Combine ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์กฐ๊ธˆ ๋” ๋…ผ์˜ํ–ˆ๊ณ  ๋‹น์‹ ์€ ์šฐ๋ฆฌ๋ฅผ ํ™•์‹ ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค :-)

๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ์งˆ๋ฌธ:

  1. ์ด ์œ ํ˜•์„ ์–ด๋””์— ๋‘˜์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ์€ ์ด์ƒํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. System.Numerics ๋Š” ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. System.Collections.Generic ๋„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๊ต์ž๊ฐ€ ์žˆ๊ณ  ํ•ด์‹ฑ์ด ์ปฌ๋ ‰์…˜ ์ปจํ…์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  2. ์•Œ ์ˆ˜ ์—†๋Š” ์ˆ˜์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ํ• ๋‹น ์—†๋Š” ๋นŒ๋” ํŒจํ„ด์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

(2) @Eilon ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ASP.NET Core(๋ฐ ๊ทธ ์ด์ „ ๋ฒ„์ „ ๋ฐ ๊ด€๋ จ ํ”„๋กœ์ ํŠธ)๋Š” HashCodeCombiner๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. https://github.com/aspnet/Common/blob/dev/src/Microsoft.Extensions.HashCodeCombiner.Sources/HashCodeCombiner.cs

( @David Fowler๋Š” ๋ช‡ ๋‹ฌ ์ „์— GitHub ์Šค๋ ˆ๋“œ์—์„œ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.)

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์ด ์‚ฌ์šฉ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค https://github.com/aspnet/Mvc/blob/760c8f38678118734399c58c2dac981ea6e47046/src/Microsoft.AspNetCore.Mvc.Razor/Internal/ViewLocationCacheKey.cs#L129 -L144

``` C#
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(IsMainPage? 1:0);
hashCodeCombiner.Add(ViewName, StringComparer.Ordinal);
hashCodeCombiner.Add(์ปจํŠธ๋กค๋Ÿฌ ์ด๋ฆ„, StringComparer.Ordinal);
hashCodeCombiner.Add(AreaName, StringComparer.Ordinal);

if (ViewLocationExpanderValues โ€‹โ€‹!= null)
{
foreach(ViewLocationExpanderValues์˜ var ํ•ญ๋ชฉ)
{
hashCodeCombiner.Add(ํ•ญ๋ชฉ.ํ‚ค, StringComparer.Ordinal);
hashCodeCombiner.Add(ํ•ญ๋ชฉ.๊ฐ’, StringComparer.Ordinal);
}
}

hashCodeCombiner๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
```

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์กฐ๊ธˆ ๋” ๋…ผ์˜ํ–ˆ๊ณ  ๋‹น์‹ ์€ ์šฐ๋ฆฌ๋ฅผ ํ™•์‹ ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค :-)

๐ŸŽ‰

์ƒˆ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ์€ ์ด์ƒํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. System.Numerics๊ฐ€ ์ž‘๋™ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ๊ฒฝ์šฐ Hash ๋ผ๋Š” ํด๋ž˜์Šค์™€ using System.Numerics ์ง€์‹œ๋ฌธ์ด ์žˆ๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋Š” ๋ชจํ˜ธํ•œ ์œ ํ˜• ์˜ค๋ฅ˜๋กœ ์ปดํŒŒ์ผ์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์•Œ ์ˆ˜ ์—†๋Š” ์ˆ˜์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ํ• ๋‹น ์—†๋Š” ๋นŒ๋” ํŒจํ„ด์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์ด๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ์œผ๋กœ, ์•„๋งˆ๋„ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ ์ด๋ฆ„์„ ์ง€์ •ํ•œ๋‹ค HashBuilder (๋ผ StringBuilder )๊ณผ์ด return this ๋ชจ๋“  ํ›„ Add ๋ฐฉ๋ฒ•๋ณด๋‹ค ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด์‹œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

public override int GetHashCode()
{
    return HashBuilder.Create(_field1)
        .Add(_field2)
        .Add(_field3)
        .ToHash();
}

@jamesqo ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•œ ํ•ฉ์˜๊ฐ€ ์žˆ์„ ๋•Œ ์ƒ๋‹จ์˜ ์ œ์•ˆ์„ ์—…๋ฐ์ดํŠธํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ตœ์ข… ๊ฒ€ํ† ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋””์ž์ธ์„ ์ฃผ๋„ํ•˜๋ฉด์„œ ์ง€๊ธˆ ๋‹น์‹ ์—๊ฒŒ ํ• ๋‹น ;-)

์ƒˆ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ๊ฒฝ์šฐ Hash ๋ผ๋Š” ํด๋ž˜์Šค์™€ using System.Numerics ์ง€์‹œ๋ฌธ์ด ์žˆ๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋Š” ๋ชจํ˜ธํ•œ ์œ ํ˜• ์˜ค๋ฅ˜๋กœ ์ปดํŒŒ์ผ์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฒฝ์šฐ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ง€์‹œ๋ฌธ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜๊ธฐ ์ „์— ์ปดํŒŒ์ผ ๋‹จ์œ„์˜ ์ •์˜๋œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ณ„์ธต์ด ์ง„ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์œ ํ˜•์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๋‹ค ํ•˜๋”๋ผ๋„ API๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์†Œ์Šค ๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•ž์œผ๋กœ ๋‚˜์•„๊ฐ€๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ๋•Œ ์ด๊ฒƒ์„ ํ”ผํ•˜๋Š” ๊ฒƒ์€ ๋น„ํ˜„์‹ค์ ์ž…๋‹ˆ๋‹ค. ๐Ÿ˜„ ์šฐ๋ฆฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋„ˆ๋ฌด ์ผ๋ฐ˜์ ์ด์ง€ ์•Š์€ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Hash ์œ ํ˜•์„ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. HashCode ๊ฐ€ ๋” ๋‚˜์„ ๊ฒƒ ๊ฐ™์•„์š”.

๋ช‡ ๊ฐ€์ง€ ์ดˆ๊ธฐ ์ œ์•ˆ์œผ๋กœ ์•„๋งˆ๋„ ์ด๋ฆ„์„ HashBuilder๋กœ ์ง€์ •ํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๊ทผ์‚ฌ์น˜๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์  ๋ฐ ๋นŒ๋”๋ฅผ ๋‹จ์ผ ์œ ํ˜•์œผ๋กœ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

``` C#
๋„ค์ž„์ŠคํŽ˜์ด์Šค System.Collections.Generic
{
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ
{
๊ณต๊ฐœ ์ •์  ์ •์ˆ˜ ๊ฒฐํ•ฉ(int ํ•ด์‹œ1, ์ •์ˆ˜ ํ•ด์‹œ2);
๊ณต๊ฐœ ์ •์  ์ •์ˆ˜ ๊ฒฐํ•ฉ(int ํ•ด์‹œ1, ์ •์ˆ˜ ํ•ด์‹œ2, ์ •์ˆ˜ ํ•ด์‹œ3);
๊ณต๊ฐœ ์ •์  ์ •์ˆ˜ ๊ฒฐํ•ฉ(int ํ•ด์‹œ1, ์ •์ˆ˜ ํ•ด์‹œ2, ์ •์ˆ˜ ํ•ด์‹œ3, ์ •์ˆ˜ ํ•ด์‹œ4);
๊ณต๊ฐœ ์ •์  ์ •์ˆ˜ ๊ฒฐํ•ฉ(int ํ•ด์‹œ1, ์ •์ˆ˜ ํ•ด์‹œ2, ์ •์ˆ˜ ํ•ด์‹œ3, ์ •์ˆ˜ ํ•ด์‹œ4, ์ •์ˆ˜ ํ•ด์‹œ5);
๊ณต๊ฐœ ์ •์  ์ •์ˆ˜ ๊ฒฐํ•ฉ(int ํ•ด์‹œ1, ์ •์ˆ˜ ํ•ด์‹œ2, ์ •์ˆ˜ ํ•ด์‹œ3, ์ •์ˆ˜ ํ•ด์‹œ4, ์ •์ˆ˜ ํ•ด์‹œ5, ์ •์ˆ˜ ํ•ด์‹œ6);

    public static long Combine(long hash1, long hash2);
    public static long Combine(long hash1, long hash2, long hash3);
    public static long Combine(long hash1, long hash2, long hash3, long hash4);
    public static long Combine(long hash1, long hash2, long hash3, long hash4, long hash5);
    public static long Combine(long hash1, long hash2, long hash3, long hash4, long hash5, longhash6);

    public static int CombineHashCodes<T1, T2>(T1 o1, T2 o2);
    public static int CombineHashCodes<T1, T2, T3>(T1 o1, T2 o2, T3 o3);
    public static int CombineHashCodes<T1, T2, T3, T4>(T1 o1, T2 o2, T3 o3, T4 o4);
    public static int CombineHashCodes<T1, T2, T3, T4, T5>(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5);
    public static int CombineHashCodes<T1, T2, T3, T4, T5, T6>(T1 o1, T2 o2, T3 o3, T4 o4, T5 o5, T6 o6);

    public void Combine(int hashCode);
    public void Combine(long hashCode);
    public void Combine<T>(T obj);
    public void Combine(string text, StringComparison comparison);

    public int Value { get; }
}

}

This allows for code like this:

``` C#
return HashCode.Combine(value1, value2);

๊ฒŒ๋‹ค๊ฐ€:

``` C#
var hashCode = ์ƒˆ๋กœ์šด HashCode();
hashCode.Combine(IsMainPage? 1:0);
hashCode.Combine(๋ณด๊ธฐ ์ด๋ฆ„, StringComparer.Ordinal);
hashCode.Combine(์ปจํŠธ๋กค๋Ÿฌ ์ด๋ฆ„, StringComparer.Ordinal);
hashCode.Combine(์˜์—ญ ์ด๋ฆ„, StringComparer.Ordinal);

if (ViewLocationExpanderValues โ€‹โ€‹!= null)
{
foreach(ViewLocationExpanderValues์˜ var ํ•ญ๋ชฉ)
{
hashCode.Combine(item.Key, StringComparer.Ordinal);
hashCode.Combine(ํ•ญ๋ชฉ.๊ฐ’, StringComparer.Ordinal);
}
}

ํ•ด์‹œ ์ฝ”๋“œ.๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
```

์ƒ๊ฐ?

๋‚˜๋Š” @jamesqo ์˜ ์—ฐ์‡„ ํ˜ธ์ถœ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค(์ธ์Šคํ„ด์Šค ๋ฉ”์†Œ๋“œ Combine ์—์„œ this ๋ฐ˜ํ™˜).

์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜๊ณ  ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋งŒ ์œ ์ง€ํ•˜๋Š” ํ•œ ...

Combine(long hashCode) ๋Š” int ์บ์ŠคํŒ…๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ง„์ •์œผ๋กœ ๊ทธ๊ฒƒ์„ ์›ํ•˜๋Š”๊ฐ€?
long ์˜ค๋ฒ„๋กœ๋“œ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@karelz ์ œ๊ฑฐํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๊ตฌ์กฐ์ฒด๋Š” ๋ฌด๋ฃŒ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ํ•ด์‹œ๋Š” ๋งค์šฐ ํ•ซํ•œ ๊ฒฝ๋กœ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •์  ๋ฉ”์„œ๋“œ๊ฐ€ ๋ณธ์งˆ์ ์œผ๋กœ ๋ฌด๋ฃŒ์ผ ๋•Œ ๋ช…๋ น์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋‘˜๋Ÿฌ์‹ธ๋Š” ๊ตฌ์กฐ์ฒด์˜ ์‹ค์ œ ์˜ํ–ฅ์„ ๋ณด์—ฌ์ค€ ์ฝ”๋“œ ๋ถ„์„์„ ๋ณด์‹ญ์‹œ์˜ค.

์ด๋ฆ„ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด Hashing ์ •์  ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ ์ฝ”๋“œ๊ฐ€ ์ข‹์•„ ๋ณด์ž…๋‹ˆ๋‹ค.

@redknightlois ํ•˜๋‚˜์˜ int ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ์ผ๋ฐ˜ ๊ตฌ์กฐ์ฒด๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋„ ๋™์ผํ•œ '๋‚˜์œ' ์ฝ”๋“œ๋ฅผ ์˜ˆ์ƒํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์ด ์—ฌ์ „ํžˆ '๋‚˜์œ' ์–ด์…ˆ๋ธ”๋ฆฌ ์ฝ”๋“œ๋ผ๋ฉด ์—ฌ๊ธฐ์—์„œ ์ตœ์ ํ™” ์ž‘์—…์„ ๋” ์ž˜ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด JIT๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์ง€์นจ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด API๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ตœํ›„์˜ ์ˆ˜๋‹จ IMO๊ฐ€ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@redknightlois ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ฒด(์ด ๊ฒฝ์šฐ HashCode )๊ฐ€ ๋ ˆ์ง€์Šคํ„ฐ์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฉด JIT๊ฐ€ ๋” ๋‚˜์œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๊นŒ? int ์ •๋„๋งŒ ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ตœ๊ทผ ๊ตฌ์กฐ์ฒด ์ฃผ๋ณ€์—์„œ ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด coreclr์—์„œ ๋งŽ์€ pull ์š”์ฒญ์„ ๋ณด๊ณ  ์žˆ์œผ๋ฉฐ dotnet/coreclr#8057์ด ์ด๋Ÿฌํ•œ ์ตœ์ ํ™”๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ JIT๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ด ๋ณ€๊ฒฝ ํ›„์— ๋” ๋‚˜์•„์งˆ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

ํŽธ์ง‘: @karelz ๊ฐ€ ์ด๋ฏธ ์—ฌ๊ธฐ์—์„œ ๋‚ด ์š”์ ์„ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์„ ๋ด…๋‹ˆ๋‹ค.

@karelz , ๋‚˜๋Š” ๋‹น์‹ ์—๊ฒŒ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. JIT๊ฐ€ int ํฌ๊ธฐ์˜ ๊ตฌ์กฐ์ฒด์— ๋Œ€ํ•ด ๊ดœ์ฐฎ์€ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด(์˜ˆ๋ฅผ ๋“ค์–ด ImmutableArray ์—๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Œ) ์ •์  ์˜ค๋ฒ„๋กœ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ค‘๋ณต๋˜๋ฉฐ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@terrajobst ๋” ๋งŽ์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋‹น์‹ ๊ณผ ๋‚˜์˜ ์•„์ด๋””์–ด๋ฅผ ์•ฝ๊ฐ„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. HashCode ์ข‹์€ ์ด๋ฆ„ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋นŒ๋” ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ์ฒด์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  int ์˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋ž˜ํผ๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ชจ๋“  Combine ์ž‘์—…์€ ์ƒˆ HashCode ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด
public struct HashCode
{
    private readonly int _hash;

    public HashCode Combine(int hash) => return new HashCode(CombineCore(_hash, hash));

    public HashCode Combine<T>(T item) => Combine(EqualityComparer<T>.Default.GetHashCode(item));
}

// Usage
HashCode combined = new HashCode(_field1)
    .Combine(_field2)
    .Combine(_field3);
  • ์‚ฌ๋žŒ๋“ค์ด ๋งˆ์ง€๋ง‰ .Value ํ˜ธ์ถœ์„ ํ•  ํ•„์š”๊ฐ€ ์—†๋„๋ก int ๋กœ์˜ ๋ณ€ํ™˜์„ ์œ„ํ•œ ์•”์‹œ์  ์—ฐ์‚ฐ์ž๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • Re Combine , ๊ทธ๊ฒŒ ์ตœ๊ณ ์˜ ์ด๋ฆ„์ธ๊ฐ€์š”? ๋” ์„ค๋ช…์ ์œผ๋กœ ๋“ค๋ฆฌ์ง€๋งŒ Add ๋Š” ๋” ์งง๊ณ  ์ž…๋ ฅํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ( Mix ๋Š” ๋˜ ๋‹ค๋ฅธ ๋Œ€์•ˆ์ด์ง€๋งŒ ์ž…๋ ฅํ•˜๊ธฐ๊ฐ€ ์•ฝ๊ฐ„ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.)

    • public void Combine(string text, StringComparison comparison) : ์ด๊ฒƒ์€ ๋ฌธ์ž์—ด๊ณผ ๊ด€๋ จ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ๊ฐ™์€ ์œ ํ˜•์— ์†ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€, ๊ทธ๋ ‡๊ฒŒ ํ•ด์•ผ ํ•˜๋Š” ๋“œ๋ฌธ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด StringComparer.XXX.GetHashCode(str) ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์ถฉ๋ถ„ํžˆ ์‰ฝ์Šต๋‹ˆ๋‹ค.

    • ์ด ์œ ํ˜•์—์„œ ๊ธด ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  long์— ๋Œ€ํ•ด ๋ณ„๋„์˜ HashCode ์œ ํ˜•์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Int64HashCode ๋˜๋Š” LongHashCode ์ž…๋‹ˆ๋‹ค.

TryRoslyn์—์„œ ์ž‘์€ ์ƒ˜ํ”Œ ๊ตฌํ˜„์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. http://tinyurl.com/zej9yux

๋‹คํ–‰ํžˆ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ข‹์€ ์†Œ์‹์€ ๊ทธ๋Œ€๋กœ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ๐Ÿ‘

image

์‚ฌ๋žŒ๋“ค์ด ๋งˆ์ง€๋ง‰ .Value ํ˜ธ์ถœ์„ ๊ฐ€์งˆ ํ•„์š”๊ฐ€ ์—†๋„๋ก int๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ์•”์‹œ์  ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ์ฝ”๋“œ๋Š” ๊ฑฐ์˜ ๊ฐ„๋‹จํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•”์‹œ์  ๋ณ€ํ™˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์•ฝ๊ฐ„ ์ •๋ฆฌ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ์ „ํžˆ ์—ฌ๋Ÿฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryHashCombiner(int h1, int h2, int h3, int h4)
        {
            var h = new HashCode(h1).Combine(h2).Combine(h3).Combine(h4);
            return h.Value;
        }

๋ฆฌ ์ฝค๋ฐ”์ธ, ๊ทธ๊ฒŒ ์ตœ๊ณ ์˜ ์ด๋ฆ„์ธ๊ฐ€์š”? ๋” ์„ค๋ช…์ ์œผ๋กœ ๋“ค๋ฆฌ์ง€๋งŒ Add๊ฐ€ ๋” ์งง๊ณ  ์ž…๋ ฅํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. (Mix๋Š” ๋˜ ๋‹ค๋ฅธ ๋Œ€์•ˆ์ด์ง€๋งŒ ์ž…๋ ฅํ•˜๊ธฐ๊ฐ€ ์•ฝ๊ฐ„ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.)

Combine์€ ํ•ด์‹ฑ ์ปค๋ฎค๋‹ˆํ‹ฐ afaik์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์‹ค์ œ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ๋‹น์‹ ์—๊ฒŒ ๊ทธ๊ฒƒ์ด ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์•„์ด๋””์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@jamesqo ๋งŽ์€ ํ•ด์‹ฑ ํ•จ์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉฐ

๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋””์ž์ธ์—์„œ ์•ž์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

        internal interface IHashCode<T> where T : struct
        {
            T Combine(T h1, T h2);
        }

        internal struct RotateHashCode : IHashCode<int>, IHashCode<long>
        {
            long IHashCode<long>.Combine(long h1, long h2)
            {
                // The jit optimizes this to use the ROL instruction on x86
                // Related GitHub pull request: dotnet/coreclr#1830
                ulong shift5 = ((ulong)h1 << 5) | ((ulong)h1 >> 27);
                return ((int)shift5 + h1) ^ h2;
            }

            int IHashCode<int>.Combine(int h1, int h2)
            {
                // The jit optimizes this to use the ROL instruction on x86
                // Related GitHub pull request: dotnet/coreclr#1830
                uint shift5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
                return ((int)shift5 + h1) ^ h2;
            }
        }

        internal struct HashCodeCombiner<T, W> where T : struct, IHashCode<W>
                                               where W : struct
        {
            private static T hasher;
            public W Value;

            static HashCodeCombiner()
            {
                hasher = new T();
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public HashCodeCombiner(W seed)
            {
                this.Value = seed;
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public HashCodeCombiner<T,W> Combine( W h1 )
            {
                Value = hasher.Combine(this.Value, h1);
                return this;
            }
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int TryHashCombinerT(int h1, int h2, int h3, int h4)
        {
            var h = new HashCodeCombiner<RotateHashCode, int>(h1).Combine(h2).Combine(h3).Combine(h4);
            return h.Value;
        }

JIT๊ฐ€ ์ด์— ๋Œ€ํ•ด ๋งค์šฐ ์„ฑ๊ฐ€์‹  ํ”„๋กค๋กœ๊ทธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์ตœ์ ํ™”๋  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ฏ€๋กœ JIT ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋จธ์ง€๋Š” ๋‹จ์ผ ๋ช…๋ น์„ ๋‚ญ๋น„ํ•˜์ง€ ์•Š๊ณ  ์›ํ•˜๋Š” ๋งŒํผ ๋‹ค์–‘ํ•œ Combiner๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธด ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ๊ฒฐํ•ฉ๊ธฐ๋ณด๋‹ค ์‹ค์ œ ํ•ด์‹œ ํ•จ์ˆ˜์— ๋” ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. cc @CarolEidt @AndyAyersMS

ํŽธ์ง‘: ์—ฌ๊ธฐ์—์„œ ๋‹จ์ผ ํ•ด์‹ฑ ๊ฐœ๋… ์šฐ์‚ฐ ์•„๋ž˜์—์„œ ์•”ํ˜ธํ™” ๋ฐ ๋น„์•”ํ˜ธํ™” ํ•ด์‹œ ๊ธฐ๋Šฅ์„ ๊ฒฐํ•ฉํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ๋Œ€ํ•ด ํฌ๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@jamesqo

๋นŒ๋” ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ์ฒด์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์•„ ์˜ˆ. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๊ทธ ํŒจํ„ด์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ž‘์—…์— ๋ถ€์ž‘์šฉ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŒจํ„ด์„ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. API๊ฐ€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” WithXxx ํŒจํ„ด์„ ๋”ฐ๋ฅด๋Š” ๊ฒฝ์šฐ ํŠนํžˆ ๋‚˜์ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ ํŒจํ„ด์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ด๋ฏ€๋กœ ํŒจํ„ด์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋‹น์‹ ๊ณผ ๋‚˜์˜ ์•„์ด๋””์–ด๋ฅผ ์•ฝ๊ฐ„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ‘, ๊ทธ๋Ÿผ ์–ด๋–จ๊นŒ์š”?

``` C#
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ
{
๊ณต๊ฐœ ์ •์  HashCode ๋งŒ๋“ค๊ธฐ(T obj);

[Pure] public HashCode Combine(int hashCode);
[Pure] public HashCode Combine(long hashCode);
[Pure] public HashCode Combine<T>(T obj);
[Pure] public HashCode Combine(string text, StringComparison comparison);

public int Value { get; }

public static implicit operator int(HashCode hashCode);

}

This allows for code like this:

``` C#
public override int GetHashCode()
{
    return HashCode.Create(value1).Combine(value2);
}

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๊ฒƒ:

``` C#
var hashCode = ์ƒˆ๋กœ์šด HashCode()
.Combine(IsMainPage ? 1:0)
.Combine(ViewName, StringComparer.Ordinal)
.Combine(์ปจํŠธ๋กค๋Ÿฌ ์ด๋ฆ„, StringComparer.Ordinal)
.Combine(์˜์—ญ ์ด๋ฆ„, StringComparer.Ordinal);

if (ViewLocationExpanderValues โ€‹โ€‹!= null)
{
foreach(ViewLocationExpanderValues์˜ var ํ•ญ๋ชฉ)
{
hashCode = hashCode.Combine(item.Key, StringComparer.Ordinal);
hashCode = hashCode.Combine(ํ•ญ๋ชฉ.๊ฐ’, StringComparer.Ordinal);
}
}

ํ•ด์‹œ ์ฝ”๋“œ.๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
```

@terrajobst ์ƒ๊ฐ:

  1. Create<T> ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด HashCode.Create(_val) ๋˜๋Š” new HashCode().Combine(_val) ๊ฐ™์€ 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ Create / Combine ๋Œ€ํ•ด ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฒซ ๋ฒˆ์งธ ํ•„๋“œ๋ฅผ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด 2์ค„์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฏ€๋กœ diff ์นœํ™”์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. string/StringComparison์„ ํ—ˆ์šฉํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์—ฌ๊ธฐ์— ์†ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. HashCode ๋Š” ๋ฌธ์ž์—ด๊ณผ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ฌธ์ž์—ด์— GetHashCode(StringComparison) API๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ• ๊นŒ์š”? (๋˜ํ•œ ์ด๋“ค ๋ชจ๋‘๋Š” string.GetHashCode ์˜ ๊ธฐ๋ณธ ๋™์ž‘์ธ ์„œ์ˆ˜ ๋น„๊ต์ž…๋‹ˆ๋‹ค.)
  3. ๊ฐ€์ง€๊ณ ์žˆ๋Š” ์  ๋ฌด์—‡ Value ์ด๋ฏธ๋กœ ๋ณ€ํ™˜ ์•”์‹œ ์  ์—ฐ์‚ฐ์ž๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ, int ? ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด๊ฒƒ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‹ค๋ฅธ ๊ฒƒ์„ ์ž‘์„ฑํ•˜๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  4. long ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ƒˆ ์œ ํ˜•์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. HashCode ๋„ˆ๋น„๋Š” 32๋น„ํŠธ์ž…๋‹ˆ๋‹ค. ๊ธธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  5. ํ•ด์‹ฑ์—์„œ ๋” ์ผ๋ฐ˜์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ช…๋˜์ง€ ์•Š์€ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ œ์•ˆํ•œ API๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public struct HashCode
{
    public HashCode Combine(int hash);
    public HashCode Combine(uint hash);
    public HashCode Combine<T>(T obj);

    public static implicit operator int(HashCode hashCode);
    public static implicit operator uint(HashCode hashCode);
}

public struct Int64HashCode
{
    public Int64HashCode Combine(long hash);
    public Int64HashCode Combine(ulong hash);

    public static implicit operator long(Int64HashCode hashCode);
    public static implicit operator ulong(Int64HashCode hashCode);
}

์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•๋งŒ์œผ๋กœ ASP.NET์˜ ์˜ˆ์ œ๋Š” ์—ฌ์ „ํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var hashCode = new HashCode()
    .Combine(IsMainPage ? 1 : 0)
    .Combine(ViewName)
    .Combine(ControllerName)
    .Combine(AreaName);

if (ViewLocationExpanderValues != null)
{
    foreach (var item in ViewLocationExpanderValues)
    {
        hashCode = hashCode.Combine(item.Key);
        hashCode = hashCode.Combine(item.Value);
    }
}

return hashCode;

@jamesqo

int ๋กœ์˜ ๋ณ€ํ™˜์„ ์œ„ํ•œ ์•”์‹œ์  ์—ฐ์‚ฐ์ž๊ฐ€ ์ด๋ฏธ ์žˆ๋Š” ๊ฒฝ์šฐ Value ๊ฐ€ ๋ฌด์Šจ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด๊ฒƒ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋‹ค๋ฅธ ๊ฒƒ์„ ์ž‘์„ฑํ•˜๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋“œ์— ๋Œ€ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ ๋””์ž์ธ ์ง€์นจ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ฒ„๋กœ๋“œ๋œ ๊ฐ ์—ฐ์‚ฐ์ž์— ํ•ด๋‹นํ•˜๋Š” ์นœ์ˆ™ํ•œ ์ด๋ฆ„์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

๋งŽ์€ ์–ธ์–ด๊ฐ€ ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์—ฐ์‚ฐ์ž๋ฅผ ์˜ค๋ฒ„๋กœ๋“œํ•˜๋Š” ํ˜•์‹์—๋Š” ๋™๋“ฑํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์ ์ ˆํ•œ ๋„๋ฉ”์ธ๋ณ„ ์ด๋ฆ„์ด ์žˆ๋Š” ๋ณด์กฐ ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ F#์€ ์•”์‹œ์  ๋ณ€ํ™˜ ์—ฐ์‚ฐ์ž๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ์–ธ์–ด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.


๋˜ํ•œ, ์ผ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•œ ๊ฐ€์ง€๋งŒ ์žˆ๋Š” ๊ฒƒ์ด ๊ทธ๋ ‡๊ฒŒ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ œ ์ƒ๊ฐ์—๋Š” API๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚œ ๊ทธ๋ƒฅ ๋ช‡ ๊ฐ€์ง€ ๊ฐ’์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์—, ๋‚˜๋Š” ์ƒ๊ฐ HashCode.CombineHashCodes(value1, value2, value3) ๋ณด๋‹ค ์ดํ•ดํ•˜๊ธฐ, ๊ฐ„๋‹จํ•œ ์งง๊ณ  ์‰ฝ๊ฒŒ new HashCode().Combine(value1).Combine(value2).Combine(value3) .

์ธ์Šคํ„ด์Šค ๋ฉ”์†Œ๋“œ API๋Š” ์—ฌ์ „ํžˆ ๋ณต์žกํ•œ ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜์ง€๋งŒ ๋” ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—๋Š” ๋” ๊ฐ„๋‹จํ•œ ์ •์  ๋ฉ”์†Œ๋“œ API๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@svick , ํ•ฉ๋ฒ•์ ์ธ ์—ฐ์‚ฐ์ž๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์š”์ . ์–‘๋ณดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด Value ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ผ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•œ ๊ฐ€์ง€๋งŒ ์žˆ๋Š” ๊ฒƒ์ด ๊ทธ๋ ‡๊ฒŒ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์‚ฌ๋žŒ์˜ ์ฝ”๋“œ๋ฅผ ์ฝ์œผ๋ฉด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ Google์— ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ๊ฐ’์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ HashCode.CombineHashCodes(value1, value2, value3)๊ฐ€ new HashCode().Combine(value1).Combine(value2).Combine( ๊ฐ€์น˜3).

  • ์ •์  ๋ฉ”์„œ๋“œ์˜ ๋ฌธ์ œ๋Š” params int[] ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ ๋‹ค๋ฅธ arity์— ๋Œ€ํ•ด ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ
  • ๋‘ ๋ฒˆ์งธ ํ˜•ํƒœ๋Š” ํ•œ๋‘ ๋ฒˆ ๋ณด๋ฉด ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ์ˆ˜์ง์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ฝ๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ฃผ์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋”ฐ๋ผ์„œ ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€/์ œ๊ฑฐ๋  ๋•Œ diff๋ฅผ ์ตœ์†Œํ™”ํ•จ).
public override int GetHashCode()
{
    return new HashCode()
        .Combine(_field1)
        .Combine(_field2)
        .Combine(_field3)
        .Combine(_field4);
}

[@svick] ์ผ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•œ ๊ฐ€์ง€๋งŒ ์žˆ๋Š” ๊ฒƒ์ด ๊ทธ๋ ‡๊ฒŒ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ˜ผ๋ž€์„ ํ”ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์˜ ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋™์‹œ์— ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ์„ฑ, ํŽธ์˜์„ฑ, ์„ฑ๋Šฅ ๋˜๋Š” ๊ฐ€๋…์„ฑ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ๋ชฉํ‘œ๋ฅผ ์‹คํ˜„ํ•˜๋Š” ๋ฐ ๋„์›€์ด๋œ๋‹ค๋ฉด 100% ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” API๋ณด๋‹ค๋Š” ๊ฐœ๋…์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์ค‘ ์˜ค๋ฒ„๋กœ๋“œ๋Š” ๋ถ„๋ฆฌ๋œ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฌธ์ œ๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ์ด์œ ๋Š” ์ดˆ๊ธฐ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค. Combine ๋’ค์— ์˜ค๋Š” ๋นˆ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋…ผ๋ฆฌ์ ์ธ ๊ฒƒ์€ .ctor๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ boxing์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” .ctor๋กœ๋Š” ํ•  ์ˆ˜ ์—†๋Š” ์ผ๋ฐ˜์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ œ๋„ค๋ฆญ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ฐจ์„ ์ฑ…์ž…๋‹ˆ๋‹ค.

์ข‹์€ ๋ถ€์ž‘์šฉ์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ฒŒ ๋ณด์ธ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  API ๋””์ž์ธ์—์„œ ์šฐ๋ฆฌ๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ๋ณด๋‹ค ์ผ๊ด€์„ฑ์„ ๊ฐ•๋ ฅํžˆ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

[@svick] ์ ์€ ์ˆ˜์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด HashCode.CombineHashCodes(value1, value2, value3)๊ฐ€ new HashCode().Combine(value1).Combine(value2)๋ณด๋‹ค ๋” ๊ฐ„๋‹จํ•˜๊ณ  ์งง๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ).๊ฒฐํ•ฉ(๊ฐ’3).

@jamesqo์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œํ•œ์˜ ์„ฑ๋Šฅ ํŒจ๋„ํ‹ฐ๋กœ ์ž„์˜์˜ ์–‘์˜ ์ธ์ˆ˜๋กœ ํ™•์žฅ๋˜๋Š” ๋นŒ๋” ํŒจํ„ด์— ๋Œ€ํ•ด ์ œ๊ฐ€ ์ข‹์•„ํ•˜๋Š” ์ (์žˆ๋Š” ๊ฒฝ์šฐ ์ธ๋ผ์ธ์ด ์–ผ๋งˆ๋‚˜ ์ข‹์€์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฆ„).

[@jamesqo] string/StringComparison์„ ์ˆ˜๋ฝํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์—ฌ๊ธฐ์— ์†ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. HashCode๋Š” ๋ฌธ์ž์—ด๊ณผ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

๊ณต์ •ํ•œ ์ง€์ ์ž…๋‹ˆ๋‹ค. @Eilon ์˜ ์ฝ”๋“œ์—์„œ ์ฐธ์กฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋ฌธ์ž์—ด์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ๋น„๊ต๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋‹จ์€ ๋†”๋‘์ž.

[@jamesqo] ๊ธด ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ƒˆ๋กœ์šด ์œ ํ˜•์œผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. HashCode ๋„ˆ๋น„๋Š” 32๋น„ํŠธ์ž…๋‹ˆ๋‹ค. ๊ธธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฑด ์ข‹์€ ์ง€์ ์ด์•ผ. long ๋ฒ„์ „์ด ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋‚ด์šฉ์ด๋ผ ๋ณ„ ์ƒ๊ฐ ์—†์ด ๊ทธ๋ƒฅ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ .NET GetHashCode() ์— ๋Œ€ํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— 32๋น„ํŠธ๋งŒ ๋‚จ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋งฅ๋ฝ์—์„œ uint ๋ฒ„์ „์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”์ง€๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜์—ญ ์™ธ๋ถ€์—์„œ ํ•ด์‹ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ System.Security.Cryptography ์— ์žˆ๋Š” ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ ๋ชฉ์ ์˜ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

```C#
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ
{
๊ณต๊ฐœ ์ •์  HashCode ๋งŒ๋“ค๊ธฐ(T obj);

[Pure] public HashCode Combine(int hashCode);
[Pure] public HashCode Combine<T>(T obj);

public int Value { get; }

public static implicit operator int(HashCode hashCode);

}
```

์ด์ œ .NET GetHashCode()๊ฐ€ ๋ฐ”๋กœ 32๋น„ํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— 32๋น„ํŠธ๋งŒ ๋‚จ๊ฒจ์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ ์—์„œ uint ๋ฒ„์ „์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”์ง€๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜์—ญ ์™ธ๋ถ€์—์„œ ํ•ด์‹ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ System.Security.Cryptography์— ์žˆ๋Š” ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ ๋ชฉ์ ์˜ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@terrajobst ์‹ค์ œ ๋™๋ฌผ์›์ธ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—๋Š” ๋งค์šฐ ๋‹ค์–‘ํ•œ ์œ ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ์•„๋งˆ๋„ 70%๋Š” ์„ค๊ณ„์ƒ ๋น„์•”ํ˜ธํ™”์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋งˆ๋„ ๊ทธ ์ค‘ ์ ˆ๋ฐ˜ ์ด์ƒ์ด 64+ ๋น„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค(๊ณตํ†ต ๋ชฉํ‘œ๋Š” 128/256). ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋‚ด๊ฐ€ ์žฅ๋‹ดํ•˜๋Š” 32๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ๊ฒƒ์€ (๋‚˜๋Š” ๊ฑฐ๊ธฐ์— ๊ฐ€์ง€ ์•Š์•˜์Œ) ๋‹น์‹œ x86์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๊ฑฐ๋Œ€ํ•œ ์†Œ๋น„์ž์˜€๊ณ  ํ•ด์‹œ๋Š” ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ฎ์€ ํ•˜๋“œ์›จ์–ด์—์„œ ์„ฑ๋Šฅ์ด ๊ฐ€์žฅ ์ค‘์š”ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ •๋ง ์ด์ƒ ์ •์˜ ๋œ ํ•ด์‹œ ํ•จ์ˆ˜์˜ ๊ฐ€์žฅ ์—„๊ฒฉํ•˜๊ธฐ uint ๋„๋ฉ”์ธ์„, ๊ทธ๋ฆฌ๊ณ ์— int ๋ณ€ํ™”์˜ ๊ทœ์น™์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์‚ฌ์‹ค ์ œ๊ฐ€ ์˜ˆ์ „์— ์˜ฌ๋ ธ๋˜ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด int ๊ฐ€ ๋ฐ”๋กœ uint ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. (๊ทธ๋ฆฌ๊ณ  ror/rol ์ตœ์ ํ™” ์‚ฌ์šฉ) ๋งŒ์ผ ์šฐ๋ฆฌ๊ฐ€ ์—„๊ฒฉํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์œ ์ผํ•œ ํ•ด์‹œ๋Š” uint ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•ด๋‹น ์กฐ๋ช… ์•„๋ž˜์—์„œ int ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๊ณผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ int ๋กœ ์ œํ•œํ•˜๋Š” ๊ฒƒ์€ ์˜ค๋Š˜๋‚  ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚ซ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ œ ์š”์ฒญ์ด๋ผ๋ฉด ๋””์ž์ธ ํŒ€์— ์š”์ฒญํ•˜์—ฌ 128๊ฐœ ๋ฐ 256๊ฐœ ๋ณ€์ข…๊ณผ ๋‹ค์–‘ํ•œ ํ•ด์‹œ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒ€ํ† ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณผ๋„ํ•œ ๋‹จ์ˆœํ™”๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋Š” ๋ณต์žกํ•œ ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์„ค๊ณ„ ๋ฌธ์ œ๋ณด๋‹ค ๋” ๋‚˜์  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ not being able to deal with having multiple options ๋กœ ์ธ์‹๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋Šฅ์„ ํฌ๊ฒŒ ๋‹จ์ˆœํ™”ํ•˜๋ฉด ํ˜„์žฌ SIMD ์ƒํƒœ์˜ ๊ฒฝ๋กœ๋กœ ์‰ฝ๊ฒŒ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์„ ์ค‘์‹œํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋Œ€๋ถ€๋ถ„์€ ์–ด์จŒ๋“  ๊ทธ๋ ‡๊ฒŒ ๋ฏธ์„ธํ•œ ์ฒ˜๋ฆฌ๋Ÿ‰ ๋ชฉํ‘œ๋ฅผ ๊ฐ€์ง„ ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค๋ฃจ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ•ด์‹ฑ์˜ ๊ฒฝ์šฐ๋„ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. 32๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋„๋ฉ”์ธ์€ ๋งค์šฐ ์ œํ•œ์ ์ด๋ฉฐ(๋Œ€๋ถ€๋ถ„์€ ์ด๋ฏธ ํ”„๋ ˆ์ž„์›Œํฌ ์ž์ฒด์—์„œ ๋‹ค๋ฃจ๊ณ  ์žˆ์Œ) ๋‚˜๋จธ์ง€๋Š” ์šด์ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

image

๋˜ํ•œ 75000๊ฐœ ์ด์ƒ์˜ ์š”์†Œ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ฆ‰์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ํ™•๋ฅ ์ด 50%์ด๋ฉฐ, ์ด๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ž˜ ์„ค๊ณ„๋œ ํ•ด์‹œ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •). ์ด๊ฒƒ์ด 64๋น„ํŠธ์™€ 128๋น„ํŠธ๊ฐ€ ๋Ÿฐํƒ€์ž„ ๊ตฌ์กฐ์˜ ๊ฒฝ๊ณ„ ๋ฐ–์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

int ์— ๊ณ ์ •๋œ ๋””์ž์ธ์œผ๋กœ ์šฐ๋ฆฌ๋Š” 2000๋…„์— ๋จผ๋ฐ์ด ์‹ ๋ฌธ์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋งŒ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์ด์ œ ๋ชจ๋‘๊ฐ€ ์Šค์Šค๋กœ ๊ฐ€๋‚œํ•œ ํ•ด์‹ฑ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค). ์˜ˆ์ˆ ๋„.

๊ทธ๊ฒƒ์€ ํ† ๋ก ์— ๋‚ด 2 ์„ผํŠธ์ž…๋‹ˆ๋‹ค.

@redknightlois , int ํ•ด์‹œ์˜ ํ•œ๊ณ„๋ฅผ ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ @terrajobst์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ Object.GetHashCode ์žฌ์ •์˜์—์„œ ํ•ด์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋ชฉ์ ์œผ๋กœ ํ•ด์‹œ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” API์— ๊ด€ํ•œ ๊ฒƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๋” ํ˜„๋Œ€์ ์ธ ํ•ด์‹ฑ์„ ์œ„ํ•œ ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ Object.GetHashCode ๋ฐ ๊ธฐ์กด์˜ ๋ชจ๋“  ํ•ด์‹ฑ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ ๋…ผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

128๋น„ํŠธ์—์„œ ํ•ด์‹œ ๊ฒฐํ•ฉ์„ ์ˆ˜ํ–‰ํ•œ ๋‹ค์Œ GetHahsCode์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก int๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์—ฌ์ „ํžˆ ์œ ์ตํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š” ํ•œ.

@KrzysztofCwalina ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” 2000๋…„์— ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ผ๋ฐ˜์ ์ธ ํ•ด์‹ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ด๊ฒƒ์ด ์ „์ž์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•œ๋‹ค๋ฉด ํ† ๋ก ์€ ๋๋‚œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ "๋ฏธ๋ž˜" ์ด์ •ํ‘œ์— ๋Œ€ํ•œ ์„ค๊ณ„ ํ† ๋ก ์˜ ๊ฒฝ์šฐ, ๋Œ€๋ถ€๋ถ„ ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ผ์ด ํ–ฅํ›„ ํ† ๋ก ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€์กฑํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์‹ค์ˆ˜๋ฅผ ํ•˜๋ฉด ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

@redknightlois , ์ €๋Š” ๋‹ค์Œ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค: ๋ฏธ๋ž˜์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ API๋ฅผ ์„ค๊ณ„ํ•ฉ์‹œ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฏธ๋ž˜ API์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋˜๋Š” ๋””์ž์ธ ์„ ํƒ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์€ c2000 API๋ฅผ corfx์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์‹œ์— corfxlab์—์„œ ๋ฏธ๋ž˜ API๋ฅผ ์‹คํ—˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@redknightlois

์—ฌ๊ธฐ์„œ ์‹ค์ˆ˜๋ฅผ ํ•˜๋ฉด ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ ๋” ๊ณ ๊ธ‰ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ง€์›ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ HashCode ์—์„œ ๋ณ„๋„์˜ ์œ ํ˜•์œผ๋กœ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ์˜ ๊ฒฐ์ •์€ ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์— ์‹ค์ œ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

@redknightlois :+1:. Btw, ๋‹น์‹ ์€ ๋‚ด๊ฐ€ ๋‚ด ์˜๊ฒฌ์„ ํŽธ์ง‘ํ•˜๊ธฐ ์ „์— ์‘๋‹ตํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ํ•ด์‹œ๊ฐ€ ๋ชจ๋“  ์œ ํ˜•(int, long, decimal ๋“ฑ)๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๊ณ  ํ•ต์‹ฌ ํ•ด์‹ฑ ๋…ผ๋ฆฌ๋ฅผ ๊ตฌ์กฐ์ฒด๋กœ ์บก์Šํ™”ํ•˜๋Š” ์•„์ด๋””์–ด(์œ„)๋ฅผ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/jamesqo/HashApi (์ƒ˜ํ”Œ ์‚ฌ์šฉ๋ฒ•์€ ์—ฌ๊ธฐ ). ๊ทธ๋Ÿฌ๋‚˜ ๋‘ ๊ฐœ์˜ ์ œ๋„ค๋ฆญ ์œ ํ˜• ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ณ  API๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์ปดํŒŒ์ผ๋Ÿฌ ์œ ํ˜• ์œ ์ถ”๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ, ์ง€๊ธˆ์€ ๋ณ„๋„์˜ ๋ฌธ์ œ๋กœ ๊ณ ๊ธ‰ ํ•ด์‹ฑ์„ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@terrajobst API๊ฐ€ ๊ฑฐ์˜ ์ค€๋น„๋œ ๊ฒƒ ๊ฐ™์ง€๋งŒ 1~2๊ฐ€์ง€ ๋” ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • HashCode.Create(x) ๋Š” new HashCode().Combine(x) ์™€ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ Create ์„ Combine ๋ฐ”๊พธ์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๊นŒ? ์ฒซ ๋ฒˆ์งธ ํ•„๋“œ์— ํ•˜๋‚˜๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ํ•„๋“œ์— ๋‹ค๋ฅธ ๊ฒƒ์„ ์ž…๋ ฅํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์†Œ ์„ฑ๊ฐ€์‹  ์ผ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • HashCode ๊ฐ€ IEquatable<HashCode> ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ๋“ฑํ˜ธ ์—ฐ์‚ฐ์ž๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด์˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์–ธ์ œ๋“ ์ง€ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

(์ž˜ํ•˜๋ฉด) ์ตœ์ข… ์ œ์•ˆ:

public struct HashCode : IEquatable<HashCode>
{
    public static HashCode Combine(int hash);
    public static HashCode Combine<T>(T obj);

    public HashCode Combine(int hash);
    public HashCode Combine<T>(T obj);

    public int Value { get; }

    public static implicit operator int(HashCode hashCode);

    public static bool operator ==(HashCode left, HashCode right);
    public static bool operator !=(HashCode left, HashCode right);

    public override bool Equals(object obj);
    public override bool Equals(HashCode other);
    public override int GetHashCode();
}

// Usage:

public override int GetHashCode()
{
    return HashCode
        .Combine(_field1)
        .Combine(_field2)
        .Combine(_field3)
        .Combine(_field4);
}

@terrajobst ๋Š” ๋‹ค์Œ๊ณผ

๊ณต์ •ํ•œ ์ง€์ ์ž…๋‹ˆ๋‹ค. @Eilon ์˜ ์ฝ”๋“œ์—์„œ ์ฐธ์กฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋ฌธ์ž์—ด์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ๋น„๊ต๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋‹จ์€ ๋†”๋‘์ž.

์‹ค์ œ๋กœ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ํ•ด์‹œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋ฌธํ™”๊ถŒ๊ณผ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„์„ ๋ชจ๋‘ ํฌํ•จํ•˜๋Š” ํ•ด๋‹น ๋ฌธ์ž์—ด์˜ ๋ชฉ์ ์„ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. StringComparer๋Š” ๋น„๊ต ์ž์ฒด์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฌธํ™”/๋Œ€์†Œ๋ฌธ์ž๋ฅผ ์ธ์‹ํ•˜๋Š” ํŠน์ • GetHashCode ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด API๊ฐ€ ์—†์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ƒํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

HashCode.Combine(str1.ToLowerInvariant()).Combine(str2.ToLowerInvariant())

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ํ• ๋‹น์œผ๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ๊ณ  ๋ฌธํ™”์— ๋ฏผ๊ฐํ•œ ํŒจํ„ด์„ ๋”ฐ๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@Eilon ์ด ๊ฒฝ์šฐ ์ฝ”๋“œ๋Š” ๋ฌธํ™”/๋Œ€์†Œ๋ฌธ์ž๋ฅผ ์ธ์‹ํ•˜๋Š” string.GetHashCode(StringComparison comparison) ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ int ๋กœ Combine ํ•ฉ๋‹ˆ๋‹ค.

c# HashCode.Combine(str1.GetHashCode(StringComparer.Ordinal)).Combine(...)

@Eilon , StringComparer.InvariantCultureIgnoreCase.GetHashCode๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ• ๋‹น ์ธก๋ฉด์—์„œ๋Š” ํ™•์‹คํžˆ ๋” ์ข‹์ง€๋งŒ ์ด๋Ÿฌํ•œ ํ˜ธ์ถœ์€ ๋ณด๊ธฐ์— ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค... ์šฐ๋ฆฌ๋Š” ํ•ด์‹œ์— ๋ฌธํ™”/๋Œ€์†Œ๋ฌธ์ž ์ธ์‹ ๋ฌธ์ž์—ด์„ ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ASP.NET ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ถฉ๋ถ„ํžˆ ๊ณตํ‰ํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ๋งํ•œ ๋ชจ๋“  ๊ฒƒ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ์ด ๋ชจ์–‘์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

``` C#
๋„ค์ž„์ŠคํŽ˜์ด์Šค System.Collections.Generic
{
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ: IEquatable
{
๊ณต๊ฐœ ์ •์  HashCode ๊ฒฐํ•ฉ(int ํ•ด์‹œ);
๊ณต๊ฐœ ์ •์  HashCode ๊ฒฐํ•ฉ(T obj);
public static HashCode Combine(๋ฌธ์ž์—ด ํ…์ŠคํŠธ, StringComparison ๋น„๊ต);

    public HashCode Combine(int hash);
    public HashCode Combine<T>(T obj);
    public HashCode Combine(string text, StringComparison comparison);

    public int Value { get; }

    public static implicit operator int(HashCode hashCode);

    public static bool operator ==(HashCode left, HashCode right);
    public static bool operator !=(HashCode left, HashCode right);

    public override bool Equals(object obj);
    public override bool Equals(HashCode other);
    public override int GetHashCode();
}

}

// ์šฉ๋ฒ•:

๊ณต๊ฐœ ์žฌ์ •์˜ int GetHashCode()
{
๋ฐ˜ํ™˜ HashCode.Combine(_field1)
.๊ฒฐํ•ฉ(_field2)
.๊ฒฐํ•ฉ(_field3)
.๊ฒฐํ•ฉ(_field4);
}
```

๋ฐฐ์†ก! :-)

@terrajobst _ ์ž ์‹œ๋งŒ--_ Combine(string, StringComparison) ํ™•์žฅ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๊นŒ?

public static class HashCodeExtensions
{
    public static HashCode Combine(this HashCode hashCode, string text, StringComparison comparison)
    {
        switch (comparison)
        {
            case StringComparison.Ordinal:
                return HashCode.Combine(StringComparer.Ordinal.GetHashCode(text));
            case StringComparison.OrdinalIgnoreCase:
                ...
        }
    }
}

์œ ํ˜• ์„œ๋ช…์˜ ์ผ๋ถ€๋ณด๋‹ค ํ™•์žฅ ๋ฐฉ๋ฒ•์„ ํ›จ์”ฌ ๋” ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹น์‹ ์ด๋‚˜ @Elion ์ด ์ด๊ฒƒ์ด ๋‚ด์žฅ๋œ ๋ฐฉ๋ฒ•์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ ˆ๋Œ€์ ์œผ๋กœ ์ƒ๊ฐํ•œ๋‹ค๋ฉด ๋‚˜๋Š” ์ด ์ œ์•ˆ์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

( ํŽธ์ง‘ : ์˜ค๋Š˜๋‚  ๋‚ด๊ฐ€ ์•Œ์ง€ ๋ชปํ•˜๋Š” Collection.Generic ์— ํ•ด์‹œ ๊ด€๋ จ ์œ ํ˜•์ด ์—†๋Š” ํ•œ System.Numerics ๋„ ์•„๋งˆ๋„ ๋” ๋‚˜์€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

LGTM. ๋‚˜๋Š” ํ™•์žฅ์„ ๊ฐˆ ๊ฒƒ์ด๋‹ค.

์˜ˆ, ํ™•์žฅ ๋ฐฉ๋ฒ•์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๊นŒ?

@terrajobst

์˜ˆ, ํ™•์žฅ ๋ฐฉ๋ฒ•์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๊นŒ?

ASP.NET ์ฝ”๋“œ์—์„œ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ๊ดœ์ฐฎ์ง€๋งŒ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ/์•ฑ์—๋Š” ํ•ด๋‹น๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚˜์ค‘์— ์ถฉ๋ถ„ํžˆ ์ผ๋ฐ˜์ ์ธ ๊ฒƒ์œผ๋กœ ํŒ๋ช…๋˜๋ฉด ์–ธ์ œ๋“ ์ง€ ์žฌํ‰๊ฐ€ํ•˜๊ณ  ๋ณ„๋„์˜ ์ œ์•ˆ์— ์ถ”๊ฐ€ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Œ ์ด๊ฑด ์–ด์จŒ๋“  ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์ผ๋‹จ ์ •์˜๋˜๋ฉด ์–ด์จŒ๋“  ์„œ๋ช…์˜ ์ผ๋ถ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋Œ“๊ธ€์„ ์Šคํฌ๋žฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค.

ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. ์œ ํ˜• ์ž์ฒด์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ  ๋ณด๊ฐ•ํ•˜๋ ค๋Š” ๊ธฐ์กด ์œ ํ˜•์ž…๋‹ˆ๋‹ค.
  2. ๋ ˆ์ด์–ด๋ง ๋ฌธ์ œ ํ•ด๊ฒฐ
  3. ํ›จ์”ฌ ๋œ ์‚ฌ์šฉ๋˜๋Š” API์—์„œ ์Šˆํผ ๊ณตํ†ต API๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” (1) ๋˜๋Š” (2)๊ฐ€ ์—ฌ๊ธฐ์— ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. (3) HashCode ์•„๋‹Œ ๋‹ค๋ฅธ ์–ด์…ˆ๋ธ”๋ฆฌ๋กœ ์ฝ”๋“œ๋ฅผ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ์ด๋™ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ฌธ์ž์—ด์ด ๊ฐ€์น˜๊ฐ€ ์—†์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ผ๋ฐ˜์ ์ด๋ผ๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์ด ๋„ˆ๋ฌด ์ผ๋ฐ˜์ ์ด์–ด์„œ ๊ทธ๊ฒƒ๋“ค์„ ํ™•์žฅ ์œ ํ˜•์—์„œ ์ธ์œ„์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ผ๊ธ‰์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฒƒ์ด ๋” ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ฃผ์žฅํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

@terrajobst , ๋ถ„๋ช…ํžˆ string API๋ฅผ ์™„์ „ํžˆ ๋ฒ„๋ฆฌ๊ณ  ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์ž์ฒด ํ™•์žฅ ๋ฐฉ๋ฒ•์„ ์ž‘์„ฑํ•˜๋„๋ก ASP.NET์— ๋งก๊ธธ ๊ฒƒ์„ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ฌธ์ž์—ด์ด ๊ฐ€์น˜๊ฐ€ ์—†์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ผ๋ฐ˜์ ์ด๋ผ๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค, ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์ด ๋„ˆ๋ฌด ์ผ๋ฐ˜์ ์ด์–ด์„œ ๊ทธ๊ฒƒ๋“ค์„ ํ™•์žฅ ์œ ํ˜•์—์„œ ์ธ์œ„์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ผ๊ธ‰์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฒƒ์ด ๋” ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ฃผ์žฅํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ํ•˜์ง€๋งŒ ๊ธฐ์กด Combine<T> ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š” ์œ ์ผํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์ธ ๋ฌธ์ž์—ด์˜ ๋น„์„œ์ˆ˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์›ํ•˜๋Š” ์‚ฌ๋žŒ์ด ์–ผ๋งˆ๋‚˜ ํ”ํ•œ๊ฐ€์š”? (์˜ˆ: ์žฌ์ •์˜์—์„œ StringComparer.CurrentCulture.GetHashCode ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‚ฌ๋žŒ?) ์ œ๊ฐ€ ํ‹€๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋งŽ์ด ๋ณด์ง€๋Š” ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ๋ฐ˜๋ฐœ์— ๋Œ€ํ•ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. API๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ, ํ•˜์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ฌธ์ž์—ด์˜ ๋น„์„œ์ˆ˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์–ป๊ณ  ์‹ถ์–ดํ•˜๋Š” ๊ฒƒ์€ ์–ผ๋งˆ๋‚˜ ํ”ํ•œ ์ผ์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ํŽธํ–ฅ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€์†Œ๋ฌธ์ž ๋ถˆ๋ณ€์„ฑ์€ ๊ฝค ์ธ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก , ๋ฌธํ™”๋ณ„ ํ•ด์‹œ ์ฝ”๋“œ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ์€ ๋งŽ์ง€ ์•Š์ง€๋งŒ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๋ฌด์‹œํ•˜๋Š” ํ•ด์‹œ ์ฝ”๋“œ๋Š” ์ œ๊ฐ€ ์™„์ „ํžˆ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  @Eilon ์ด StringComparison.OrdinalIgnoreCase ).

์ด์— ๋Œ€ํ•œ ๋ฐ˜๋ฐœ์— ๋Œ€ํ•ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. API๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋†๋‹ด์ด ์•„๋‹ˆ๋ผ ๐Ÿ˜ˆ ๋™์˜ํ•˜์ง€๋งŒ API๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ์œ ์šฉํ•˜๊ณ  ํ•ด๋ฅผ ๋ผ์น˜ ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@terrajobst ์ข‹์•„, ๊ทธ๋Ÿผ ์ถ”๊ฐ€ํ•˜์ž @redknightlois๊ฐ€ ์ œ์•ˆํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์•ž์œผ๋กœ ํ•ด์‹ฑ ๊ด€๋ จ ์œ ํ˜•์„ ๋” ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด Collections์—์„œ ์ž˜๋ชป๋œ ์ด๋ฆ„์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ข‹์•„ํ•ด. ๐Ÿ”

๋‚˜๋Š” ํ•ด์‹ฑ์ด ๊ฐœ๋…์ ์œผ๋กœ ์ปฌ๋ ‰์…˜์— ์†ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. System.Runtime์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋™์ผํ•˜๊ฑฐ๋‚˜ ์‹ฌ์ง€์–ด ์‹œ์Šคํ…œ์„ ์ œ์•ˆํ•˜๋ ค๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ˆซ์ž๋„ ์•„๋‹™๋‹ˆ๋‹ค.

@karelz , System.Runtime์ด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @redknightlois ์‹œ์Šคํ…œ์€ ์ด๋ฏธ ํ•ด๋‹น ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ ธ์™”์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ํŽธ๋ฆฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์ด ์ ์ ˆํ•œ์ง€ ์—ฌ๋ถ€๋Š” ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ๋” ๋งŽ์€ ํ•ด์‹ฑ ์œ ํ˜•์ด ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ).

๋‚œํ•ดํ•˜๊ณ  ๋งค์šฐ ์ „๋ฌธ์ ์ธ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ System.Runtime ์— ๋„ฃ์œผ๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” @KrzysztofCwalina ์™€ ์ด์•ผ๊ธฐํ–ˆ๊ณ  ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์ด ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • System
  • System.Collections.*

์šฐ๋ฆฌ๋Š” ๋‘˜ ๋‹ค System ์ชฝ์œผ๋กœ ๊ธฐ์šธ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ด System ํ•˜๋Š” ์ด์œ ๋ผ๋ฉด ์ •๋‹นํ™”๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” object.GetHashCode() ๊ตฌํ˜„์„ ๋•๊ธฐ ์œ„ํ•ด HashCode ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

@terrajobst ๊ทธ๋Ÿฌ๋ฉด System ๊ฐ€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ž :shipit:

์„ค๋ช…์—์„œ API ์‚ฌ์–‘์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

[@redknightlois] ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ด System ํ•˜๋Š” ์ด์œ ๋ผ๋ฉด ์ •๋‹นํ™”๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” object.GetHashCode() ๊ตฌํ˜„์„ ๋•๊ธฐ ์œ„ํ•ด HashCode ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

์ €์™€ @KrzysztofCwalina ๋„ ์‚ฌ์šฉํ•œ ๊ทผ๊ฑฐ์˜€์Šต๋‹ˆ๋‹ค. ํŒ๋งค ๋œ!

@jamesqo

๋‚˜๋Š” ๋‹น์‹ ์ด ๊ตฌํ˜„๊ณผ ํ•จ๊ป˜ PR๋„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๊นŒ?

@terrajobst ๋„ค, ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„์„ ๋‚ด์–ด ๊ฒ€ํ† ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋„ค, ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค.

๋‹ฌ์ฝคํ•œ. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๊ท€ํ•˜์—๊ฒŒ ๋งก๊ธฐ๊ฒ ์Šต๋‹ˆ๋‹ค. @karelz๋‹˜ ์ž˜ ์ง€๋‚ด์‹œ์ฃ ?

์‹œ๊ฐ„์„ ๋‚ด์–ด ๊ฒ€ํ† ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„์„ ๋‚ด์–ด API ํ˜•ํƒœ์— ๋Œ€ํ•ด ์ž‘์—…ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์€ ๊ณ ํ†ต์Šค๋Ÿฌ์šด ๊ณผ์ •์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–‘ํ•ดํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ €๋Š” ASP.NET Core ๊ตฌํ˜„์„ ์‚ญ์ œํ•˜๊ณ  ๋Œ€์‹  ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ๊ณ ๋Œ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

public static HashCode Combine(๋ฌธ์ž์—ด ํ…์ŠคํŠธ, StringComparison ๋น„๊ต);
public HashCode Combine(๋ฌธ์ž์—ด ํ…์ŠคํŠธ, StringComparison ๋น„๊ต);

NIT ๋‹ค์Œ ๋ฉ”์†Œ๋“œ String ์ด ๊ฑธ๋ฆด StringComparison (์˜ˆ Equals , Compare , StartsWith , EndsWith ๋“ฑ .)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ comparisonType ๋งค๊ฐœ ๋ณ€์ˆ˜์˜ ์ด๋ฆ„,ํ•˜์ง€๋กœ comparison . ์—ฌ๊ธฐ์—์„œ๋„ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ comparisonType ๋กœ ์ง€์ •ํ•ด์•ผ ์ผ๊ด€์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@justinvp , ๊ทธ๊ฒƒ์€ String ๋ฉ”์†Œ๋“œ์˜ ๋ช…๋ช… ๊ฒฐํ•จ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. Type ์€(๋Š”) ์ค‘๋ณต๋ฉ๋‹ˆ๋‹ค. ์ด์ „ API์˜ "์„ ๋ก€๋ฅผ ๋”ฐ๋ฅด๊ธฐ" ์œ„ํ•ด ์ƒˆ API์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋” ์žฅํ™ฉํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋กœ xUnit ์€ comparisonType ๋„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.

@justinvp ๋‹น์‹ ์€ ๋‚˜๋ฅผ ์„ค๋“ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ง๊ด€์ ์œผ๋กœ ์ƒ๊ฐํ•ด๋ณด๋ฉด "๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š์Œ" ๋˜๋Š” "๋ฌธํ™” ์ข…์†์ "์€ ๋น„๊ต์˜ '์œ ํ˜•'์ž…๋‹ˆ๋‹ค. ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์˜ ๋ชจ์–‘์— ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ์ธ StringComparison์— ๊ด€ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ํฌํ•จํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

``` C#
public static HashCode Combine(๋ฌธ์ž์—ด ํ…์ŠคํŠธ, StringComparison ๋น„๊ต);
public HashCode Combine(๋ฌธ์ž์—ด ํ…์ŠคํŠธ, StringComparison ๋น„๊ต);

Instead, add a method:

``` C#
public class StringComparer
{
    public static StringComparer FromComparison(StringComparison comparison);
    ...
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹ :

``` C#
๊ณต๊ฐœ ์žฌ์ •์˜ int GetHashCode()
{
๋ฐ˜ํ™˜ HashCode.Combine(_field1)
.๊ฒฐํ•ฉ(_field2)
.๊ฒฐํ•ฉ(_field3)
.Combine(_field4, _๋น„๊ต);
}

you write:

``` C#
public override int GetHashCode()
{
    return HashCode.Combine(_field1)
                   .Combine(_field2)
                   .Combine(_field3)
                   .Combine(StringComparer.FromComparison(_comparison).GetHashCode(_field4));
}

์˜ˆ, ์กฐ๊ธˆ ๋” ๊ธธ์ง€๋งŒ HashCode(๋ฐฉ๊ธˆ ์‹œ์Šคํ…œ์œผ๋กœ ์Šน๊ฒฉํ•œ)์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ํŠน์ˆ˜ ๋ฉ”์„œ๋“œ ์—†์ด ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๊ด€๋ จ ์—†๋Š” ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ •์  ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด๋ฏธ StringComparer๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค(๋น„๊ต์ž ์˜ค๋ฒ„๋กœ๋“œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—).

C# public override int GetHashCode() { return HashCode.Combine(_field1) .Combine(_field2) .Combine(_field3) .Combine(_comparer.GetHashCode(_field4)); }

@stephentoub , FromComparison ์ข‹์€ ์ƒ๊ฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์Šค๋ ˆ๋“œ์—์„œ ์œ„์ชฝ์œผ๋กœ ์ œ์•ˆํ•˜์—ฌ string.GetHashCode(StringComparison) API๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์˜ˆ์ œ๋ฅผ ํ›จ์”ฌ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค(null์ด ์•„๋‹Œ ๋ฌธ์ž์—ด๋กœ ๊ฐ€์ •).

public override int GetHashCode()
{
    return HashCode.Combine(_field1)
                   .Combine(_field2)
                   .Combine(_field3)
                   .Combine(_field4.GetHashCode(_comparison));
}

@Elion ์€ ๋„ˆ๋ฌด ๋งŽ์€ ํ˜ธ์ถœ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

(ํŽธ์ง‘: ๊ท€ํ•˜์˜ API์— ๋Œ€ํ•œ ์ œ์•ˆ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.)

๋˜ํ•œ ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด HashCode ์— 2๊ฐœ์˜ ํŠน์ˆ˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ์‹ซ์–ดํ•ฉ๋‹ˆ๋‹ค.
@Eilon ๋‹น์‹ ์ด ์–ธ๊ธ‰ํ•œ ํŒจํ„ด์€ ASP.NET Core ์ž์ฒด์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์–ผ๋งˆ๋‚˜ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

@jamesqo ๋””์ž์ธ์„ @terrajobst๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ๊ท€ํ•˜์˜ ๋„์›€๊ณผ ์ธ๋‚ด์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ์ž‘์€ API๋Š” ๋•Œ๋•Œ๋กœ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. :)

์ด API ํ”ผ๋“œ๋ฐฑ์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์ด ์–ด๋””์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ๋‹ค์Œ ๊ตฌํ˜„์„ ๊ณ„์† ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

C# public static HashCode Combine<T>(T obj, IEqualityComparer<T> cmp);

?

(์ด๋ฏธ ์‚ญ์ œ๋˜์–ด ์—ฌ๊ธฐ์—์„œ ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.)

@stephentoub ๋Š” ๋‹ค์Œ๊ณผ

์“ฐ๋‹ค:

c# public override int GetHashCode() { return HashCode.Combine(_field1) .Combine(_field2) .Combine(_field3) .Combine(StringComparer.FromComparison(_comparison).GetHashCode(_field4)); }

์˜ˆ, ์กฐ๊ธˆ ๋” ๊ธธ์ง€๋งŒ HashCode(๋ฐฉ๊ธˆ ์‹œ์Šคํ…œ์œผ๋กœ ์Šน๊ฒฉํ•œ)์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ํŠน์ˆ˜ ๋ฉ”์„œ๋“œ ์—†์ด ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๊ด€๋ จ ์—†๋Š” ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ •์  ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด๋ฏธ StringComparer๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค(๋น„๊ต์ž ์˜ค๋ฒ„๋กœ๋“œ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—).


๊ธ€์Ž„์š”, ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ์กฐ๊ธˆ ๋” ๊ธด ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ •๋ง ๋” ๊ธธ์–ด์ง€๊ณ  ๋ฐœ๊ฒฌ ๊ฐ€๋Šฅ์„ฑ์ด ์ „ํ˜€ ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์ €ํ•ญ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์œ ์šฉํ•˜๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๊ณ  ํ•˜๋Š” ์ผ์— ๋ชจํ˜ธํ•จ์ด ์—†๋‹ค๋ฉด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ •์  ๋„์šฐ๋ฏธ/๋ณ€ํ™˜ ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ• ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์„ ํฌ์ƒํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ํŽธ์˜ ๋ฐฉ๋ฒ•์„ ํฌ์ƒํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜์—๊ฒŒ ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์— ์ •๋ง ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ASP.NET์ด ๋‹ค์–‘ํ•œ ์œ„์น˜์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ตฐ๋ฐ? ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ค‘ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๊ณณ์—์„œ ์•Œ๋ ค์ง„ ๊ฐ’์ด ์•„๋‹ˆ๋ผ ์‹ค์ œ๋กœ ๋ณ€์ˆ˜ StringComparison์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ๊ฒฝ์šฐ ๋‚ด๊ฐ€ ์–ธ๊ธ‰ํ•œ ๋„์šฐ๋ฏธ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

``` C#
.Combine(StringComparer.InvariantCulture.GetHashCode(_field4))

which in no way seems onerous to me or any more undiscoverable than knowing about StringComparison and doing:

``` C#
.Combine(_field4, StringComparison.InvariantCulture);

๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด Combine ๋‚ด๋ถ€์—์„œ ๋ถ„๊ธฐํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์ฝ”๋“œ๊ฐ€ ๊ทธ ํ•œ ๊ฐ€์ง€ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ํŠน์ˆ˜ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ์Šต๋‹ˆ๊นŒ? StringComparer์— ๋Œ€ํ•œ ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์•„๋‹Œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? EqualityComparer์— ๊ณผ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? Func<T, int> ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์•„๋‹Œ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์–ด๋Š ์‹œ์ ์—์„œ ๋‹น์‹ ์€ ์„ ์„ ๊ทธ๋ฆฌ๊ณ  "์ด ๊ณผ๋ถ€ํ•˜๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฐ€์น˜๋Š” ๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค"๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์€ ์œ ์ง€ ๋น„์šฉ์ด๋“ , ์ฝ”๋“œ ํฌ๊ธฐ ๋น„์šฉ์ด๋“ , ๋ฌด์—‡์ด๋“  ๋น„์šฉ์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. , ๊ฐœ๋ฐœ์ž๊ฐ€ ์ด ์ผ€์ด์Šค๋ฅผ ์ •๋ง๋กœ ํ•„์š”๋กœ ํ•œ๋‹ค๋ฉด, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋” ์ ์€ ์ˆ˜์˜ ํŠน์ˆ˜ ์ผ€์ด์Šค๋กœ ์ฒ˜๋ฆฌํ•  ์ถ”๊ฐ€ ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” ์„ ์„ ๊ทธ์„ ์ˆ˜ ์žˆ๋Š” ์ ์ ˆํ•œ ์žฅ์†Œ๊ฐ€ ์˜ค๋ฒ„๋กœ๋“œ ์ดํ›„๊ฐ€ ์•„๋‹ˆ๋ผ ์ด๋Ÿฌํ•œ ์˜ค๋ฒ„๋กœ๋“œ ์ด์ „์ผ ๊ฒƒ์ด๋ผ๊ณ  ์ œ์•ˆํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ์ด์ „ ์‘๋‹ต์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด "๋‚˜๋Š” ์ด ๋ชจ์–‘์œผ๋กœ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค"ํ•˜๊ณ  ๋Œ€์•ˆ์„ ์ œ์•ˆํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค) .

๋‚ด๊ฐ€ ํ•œ ๊ฒ€์ƒ‰์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. https://github.com/search?p=2&q=user%3Aaspnet+hashcodecombiner&type=Code&utf8=%E2%9C%93

~100๊ฐœ์˜ ์ผ์น˜ ํ•ญ๋ชฉ ์ค‘ ์ฒ˜์Œ ๋ช‡ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ๊ฑฐ์˜ ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์—๋Š” ๋ฌธ์ž์—ด์ด ์žˆ์œผ๋ฉฐ ์—ฌ๋Ÿฌ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ๋ฌธ์ž์—ด ๋น„๊ต๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/77ed9f22fc8894fbce796bb8a704d6cd03a3b226/src/Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources/TagHelperAttributeDescriptorComparer.cs
  2. ์„œ์ˆ˜ + IgnoreCase: https://github.com/aspnet/Razor/blob/bdbb854bdbde260b3c70f565a93ebbb185a7c5a7/src/Microsoft.AspNetCore.Razor/Compilation/TagHelpers/TagHelperRequiredAttributeDescriptor
  3. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/bdbb854bdbde260b3c70f565a93ebbb185a7c5a7/src/Microsoft.AspNetCore.Razor/Chunks/Generators/AttributeBlockChunkGenerator.cs#L58
  4. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/77ed9f22fc8894fbce796bb8a704d6cd03a3b226/src/Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources/TagHelperDesignTimeDescriptor.cs#L4Comparer.
  5. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/dbcb6901209859e471c9aa978912cf7d6c178668/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/AttributeBlockChunkGenerator.cs#L56
  6. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/77ed9f22fc8894fbce796bb8a704d6cd03a3b226/src/Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources/CaseSensitiveTagHelper.cs#L6Compar2
  7. ์„œ์ˆ˜ + ์ผ€์ด์Šค ๋ฌด์‹œ: https://github.com/aspnet/dnx/blob/bebc991012fe633ecac69675b2e892f568b927a5/src/Microsoft.Dnx.Tooling/NuGet/Core/PackageSource/PackageSource.cs#L107
  8. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/bdbb854bdbde260b3c70f565a93ebbb185a7c5a7/src/Microsoft.AspNetCore.Razor/Tokenizer/Symbols/SymbolBase.cs#L52
  9. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/77ed9f22fc8894fbce796bb8a704d6cd03a3b226/src/Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources/CaseSensitiveTagHelperAttributeComparer.
  10. ์„œ์ˆ˜: https://github.com/aspnet/Razor/blob/77ed9f22fc8894fbce796bb8a704d6cd03a3b226/src/Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources/TagHelperAttributeDesignTimeDescriptor4Comparer

(๊ทธ๋ฆฌ๊ณ  ์ˆ˜์‹ญ๋ช…์˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค.)

๋”ฐ๋ผ์„œ ํ™•์‹คํžˆ ASP.NET Core ์ฝ”๋“œ๋ฒ ์ด์Šค ๋‚ด์—์„œ ์ด๊ฒƒ์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋‹ค๋ฅธ ์‹œ์Šคํ…œ๊ณผ ๋Œ€ํ™”ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

~100๊ฒฝ๊ธฐ ์ค‘

๋‹น์‹ ์ด ๋‚˜์—ดํ•œ 10๊ฐœ ์ค‘ ํ•˜๋‚˜(๋‚˜๋จธ์ง€ ๊ฒ€์ƒ‰์€ ๋ณด์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค)๋Š” ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฌธ์ž์—ด ๋น„๊ต๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฐจ์ด์ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

``` C#
.Combine(์ด๋ฆ„, StringComparison.OrdinalIgnoreCase)

``` C#
.Combine(StringComparer.OrdinalIgnoreCase.GetHashCode(Name))

? ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ํ•œ "์ •๋ง ๋” ์ด์ƒ"์ด ์•„๋‹ˆ๋ฉฐ ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

์–ด์จŒ๋“ , ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด, ๋‚˜๋Š” ๋‹จ์ˆœํžˆ ์šฐ๋ฆฌ๊ฐ€ ์ด๋Ÿฌํ•œ ๊ณผ๋ถ€ํ•˜๊ฐ€ ํ•„์š”ํ•œ์ง€ ์—ฌ๋ถ€๋ฅผ ์ •๋ง๋กœ ๊ณ ๋ คํ•  ๊ฒƒ์„ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๋ ‡๋‹ค๊ณ  ๋ฏฟ๊ณ  ์žˆ๊ณ  ์šฐ๋ฆฌ ์ž์‹ ์˜ ASP.NET ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๊ณ ๋ คํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

๊ด€๋ จํ•˜์—ฌ null ์ž…๋ ฅ์— ๋Œ€ํ•ด ๊ณ„ํš ์ค‘์ธ ๋™์ž‘์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? int==0์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? StringComparer.GetHashCode๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ null ์ž…๋ ฅ์— ๋Œ€ํ•ด throwํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฏ€๋กœ null์„ ์ „๋‹ฌํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๋ฉด ๋ฌธ์ž์—ด ์˜ค๋ฒ„๋กœ๋“œ์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ด์ ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์ด ์‹ค์ œ๋กœ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ํ˜ธ์ถœ์ž๊ฐ€ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ null. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋˜ํ•œ null์ด ์ œ๊ณต๋  ๋•Œ ๋™์ž‘์ด ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์„ ์ œ๊ธฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฐ’๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•ด์‹œ ์ฝ”๋“œ์— 0์ด ํ˜ผํ•ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์€ nop ๋ฐ ํ•ด์‹œ ์ฝ”๋“œ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๊นŒ?

null์— ๋Œ€ํ•œ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์€ 0์„ ํ˜ผํ•ฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋œ ๋‹จ์ผ null ์š”์†Œ์˜ ๊ฒฝ์šฐ nop์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€ ์‹œํ€€์Šค๋กœ ๊ณต๊ธ‰ํ•˜๋Š” ๊ฒฝ์šฐ 10๊ฐœ์˜ null ํ•ด์‹œ๋ฅผ 20๊ณผ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ๋‚ด ํˆฌํ‘œ๋Š” ๋ฌธ์ž์—ด์„ ์ธ์‹ํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ๋งค์šฐ ๋„์›€์ด ๋˜๋Š” ASP.NET Core์˜ ์ฝ”๋“œ๋ฒ ์ด์Šค ๊ด€์ ์—์„œ ๋‚˜์˜จ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ค„ ๊ธธ์ด์— ๊ด€ํ•œ ๊ฒƒ์€ ๋‚ด ์ฃผ์š” ๊ด€์‹ฌ์‚ฌ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ์„ฑ์— ๊ด€ํ•œ ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ์—์„œ ๋ฌธ์ž์—ด ์ธ์‹ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ASP.NET Core์— ๋‚ด๋ถ€ ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ์—์„œ ๋ฌธ์ž์—ด ์ธ์‹ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ASP.NET Core์— ๋‚ด๋ถ€ ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ API๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ASP.NET Core ์ฝ”๋“œ ๊ธฐ๋ฐ˜ ์™ธ๋ถ€์—์„œ๋„ ํ•„์š”ํ•˜๋‹ค๋Š” ๋” ๋งŽ์€ ์ฆ๊ฑฐ๋ฅผ ๋ณผ ๋•Œ๊นŒ์ง€๋Š” ์ด๊ฒƒ์ด ํ˜„์žฌ๋กœ์„œ๋Š” ํ›Œ๋ฅญํ•œ ์†”๋ฃจ์…˜์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

string ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ œ๊ฑฐํ•  ๋•Œ ๊ฐ’์„ ๋ณผ ์ˆ˜ ์—†๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋ณต์žก์„ฑ์„ ์ค„์ด์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ๋” ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉฐ StringComparison ์—์„œ StringComparer ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋‹ค๋ฅธ ์˜์—ญ์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ๋ฐฉํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StringComparison . .NET์€ ํ•ญ์ƒ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ์ค‘์ ์„ ๋‘์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ๋ฌธ ์„คํƒ•์€ _์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค_. ๋˜ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์ผ์„ ํ•˜๊ณ  ์„ฑ๊ณต์˜ ๊ตฌ๋ฉ์ด์— ๋น ์ง€๋„๋ก ์•ˆ๋‚ดํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฌธ์ž์—ด์ด ํŠน๋ณ„ํ•˜๊ณ  ๋ฏฟ์„ ์ˆ˜ ์—†์„ ์ •๋„๋กœ ํ”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์ธ์‹ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋“ค์„ ์ „๋ฌธํ™”ํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ์šฐ๋ฆฌ๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ๋‹ฌ์„ฑํ•ฉ๋‹ˆ๋‹ค:

  1. @Eilon ๊ณผ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  2. ๋ฌธ์ž์—ด, ํŠนํžˆ ๋Œ€์†Œ๋ฌธ์ž ๋น„๊ต๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ @Eilon ํ™•์žฅ ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ์ƒ์šฉ๊ตฌ ๋„์šฐ๋ฏธ๋Š” ์ข‹์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‚˜์œ ๊ฒƒ์ž„์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๋‚ญ๋น„๋˜๊ณ  ์ œ๋Œ€๋กœ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์œผ๋ฉด ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ ํŒฝ์ฐฝ๊ณผ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ฃผ์š” ๊ด€์‹ฌ์‚ฌ๊ฐ€ ํŠน์ˆ˜ ๋Œ€/์†Œ๋ฌธ์ž string ๊ฒฝ์šฐ ๋‹ค์Œ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

``` C#
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ: IEquatable
{
๊ณต๊ฐœ HashCode ๊ฒฐํ•ฉ(T obj, IEqualityComparer๋น„๊ต์ž);
}

// ์šฉ๋ฒ•
๋ฐ˜ํ™˜ HashCode.Combine(_numberField)
.Combine(_stringField, StringComparer.OrdinalIgnoreCase);
```

@terrajobst , ๋‹น์‹ ์˜ ํƒ€ํ˜‘์€ ์˜๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์ด์ƒ GetHashCode ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€ ๊ด„ํ˜ธ ์„ธํŠธ๋ฅผ ์ค‘์ฒฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ์ ์ด ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค.

(ํŽธ์ง‘: ์Šค๋ ˆ๋“œ์—์„œ ์•ž์„œ ์–ธ๊ธ‰ํ•œ @JonHanna ๋•๋ถ„์— ์ •๋ง ํฌ๋ ˆ๋”ง์„ ๊ฐ™์€๋ฐ์š” ? ๐Ÿ˜„ )

@JonHanna ์˜ˆ, null ์ž…๋ ฅ๋„ 0์œผ๋กœ ํ•ด์‹œํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋Œ€ํ™”๋ฅผ ๋ฐฉํ•ดํ•ด์„œ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒˆ ์œ ํ˜•์„ ์–ด๋””์— ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? @mellinoe @ericstj @weshaggard , System.HashCode ์™€ ๊ฐ™์€ ์ด ์œ ํ˜•์— ๋Œ€ํ•œ ์ƒˆ ์–ด์…ˆ๋ธ”๋ฆฌ/ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ System.Runtime.Extensions ์™€ ๊ฐ™์€ ๊ธฐ์กด ์–ด์…ˆ๋ธ”๋ฆฌ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”.

์šฐ๋ฆฌ๋Š” ์ตœ๊ทผ์— .NET Core์˜ ์–ด์…ˆ๋ธ”๋ฆฌ ๋ ˆ์ด์•„์›ƒ์„ ์ƒ๋‹นํžˆ ๋ฆฌํŒฉํ† ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. System.Runtime.Extensions ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ๊ตฌ์ฒด์ ์ธ ๋น„๊ต์ž๊ฐ€ ์žˆ๋Š” ๊ณณ์— ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@weshaggard?

@terrajobst ์ œ์•ˆ ์ž์ฒด์™€ ๊ด€๋ จํ•˜์—ฌ Combine ๋ชจ๋‘ ์ง€์ •ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฉ๊ธˆ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ๐Ÿ˜ข

๋‹ค์Œ์€ ์ธ์Šคํ„ด์Šค ๋ฐ ์ •์  ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์ด ๊ฐ™์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผ๋Ÿฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.

using System;
using System.Collections.Generic;

public struct HashCode
{
    public void Combine(int i)
    {
    }

    public static void Combine(int i)
    {
    }
}

์ด์ œ 2๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ •์  ์˜ค๋ฒ„๋กœ๋“œ์˜ ์ด๋ฆ„์„ Create , Seed ๋“ฑ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • ์ •์  ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ๋‹ค๋ฅธ ์ •์  ํด๋ž˜์Šค๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
public static class Hash
{
    public static HashCode Combine(int hash);
}

public struct HashCode
{
    public HashCode Combine(int hash);
}

// Usage:
return Hash.Combine(_field1)
           .Combine(_field2)
           .Combine(_field3);

์ €๋Š” ํ›„์ž๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์œ ๊ฐ์ด์ง€๋งŒ... ์ƒ๊ฐ์€?

๋…ผ๋ฆฌ๋ฅผ 2๊ฐ€์ง€ ์œ ํ˜•์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ด์ƒํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. HashCode ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์—ฐ๊ฒฐ์„ ๋งŒ๋“ค๊ณ  ๋Œ€์‹  Hash ํด๋ž˜์Šค๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฐจ๋ผ๋ฆฌ Create ๋ฉ”์„œ๋“œ(๋˜๋Š” Seed ๋˜๋Š” Init )๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” ๋˜ํ•œ no-args ์˜ค๋ฒ„๋กœ๋“œ HashCode.Create().Combine(_field1).Combine(_field2) ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@karelz , ๊ฐ™์€ ์ด๋ฆ„์ด ์•„๋‹Œ ๊ฒฝ์šฐ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ์ƒ์„ฑ์ž new ๊ฐ€ ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์— ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ e๋Š” ๊ตฌ์กฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ๋žŒ๋“ค์ด new HashCode().Combine ๋ฅผ ์“ฐ๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

public override int GetHashCode()
{
    return new HashCode()
        .Combine(_field1)
        ...
}

์ด๊ฒƒ์€ ํ•ด์‹œ ์ฝ”๋“œ์—์„œ ์ง์ ‘ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋Œ€์‹  0 ๋ฐ _field1 ์˜ ํ•ด์‹œ ์ฝ”๋“œ์™€ ์ถ”๊ฐ€ ๊ฒฐํ•ฉ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉ ํ•˜๊ณ  ์žˆ๋Š”

์ œ์•ˆ๋œ API(์—…๋ฐ์ดํŠธ๋œ ์‚ฌ์–‘):

namespace System
{
    public struct HashCode : IEquatable<HashCode>
    {
        public HashCode Combine(int hash);
        public HashCode Combine<T>(T obj);
        public HashCode Combine<T>(T obj, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCode hashCode);

        public static bool operator ==(HashCode left, HashCode right);
        public static bool operator !=(HashCode left, HashCode right);

        public override bool Equals(object obj);
        public override bool Equals(HashCode other);
        public override int GetHashCode();
    }
}

@redknightlois @JonHanna @stephentoub @Eilon , ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์™€ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์˜๊ฒฌ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์™€ ์ถฉ๋Œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •์  Combine ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

HashCode.Create(field1).Combine(field2) // ...

// or, using default constructor

new HashCode().Combine(field1).Combine(field2) // ...

์ฒซ ๋ฒˆ์งธ์˜ ์žฅ์ ์€ ์กฐ๊ธˆ ๋” ๊ฐ„๊ฒฐํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ์˜ ์žฅ์ ์€ ์ผ๊ด€๋œ ์ด๋ฆ„ ์ง€์ •์„ ๊ฐ€์ง€๋ฏ€๋กœ ์ฒซ ๋ฒˆ์งธ ํ•„๋“œ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๊ฒƒ์„ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๊ฐ€๋Šฅ์„ฑ์€ Combine ํŒฉํ† ๋ฆฌ๊ฐ€ ์žˆ๋Š” ์œ ํ˜•๊ณผ Combine ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ๋Š” ์œ ํ˜•(๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ์œ ํ˜•์˜ ํ™•์žฅ์ธ ๋‘ ๋ฒˆ์งธ ์œ ํ˜•)์˜ ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์œ ํ˜•์ž…๋‹ˆ๋‹ค.

์–ด๋Š ๊ฒƒ์ด TBH๋ฅผ ์„ ํ˜ธํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@JonHanna , ์ธ์Šคํ„ด์Šค ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ํ™•์žฅ ๋ฉ”์†Œ๋“œ๋ผ๋Š” ๋‘ ๋ฒˆ์งธ ์•„์ด๋””์–ด๋Š” ํ›Œ๋ฅญํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ์ฆ‰, hc.Combine(obj) ์ด ๊ฒฝ์šฐ ์ •์  ๊ณผ๋ถ€ํ•˜: TryRoslyn ์„ ์„ ํƒํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ๋ช‡ ๊ฐ€์ง€ ์˜๊ฒฌ์„ ์‹œ์ž‘์  ์œผ๋กœ ์ •์  ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ œ์•ˆํ–ˆ๋Š”๋ฐ, ์ด๋Š” ์ €์—๊ฒŒ ์ƒ๊ธฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค...

๋…ผ๋ฆฌ๋ฅผ 2๊ฐ€์ง€ ์œ ํ˜•์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ด์ƒํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. HashCode๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์—ฐ๊ฒฐ์„ ๋งŒ๋“ค๊ณ  ๋Œ€์‹  Hash ํด๋ž˜์Šค๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ๋žŒ๋“ค์€ ์–ด๋–ค ์—ฐ๊ฒฐ์„ ํ•ด์•ผ ํ• ๊นŒ์š”? ๋จผ์ € Hash ๋ฅผ ์†Œ๊ฐœํ•œ ๋‹ค์Œ ๊ฑฐ๊ธฐ์—์„œ HashCode ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ƒˆ๋กœ์šด ์ •์  ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋…ผ๋ฆฌ๋ฅผ 2๊ฐ€์ง€ ์œ ํ˜•์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ด์ƒํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. HashCode๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์—ฐ๊ฒฐ์„ ๋งŒ๋“ค๊ณ  ๋Œ€์‹  Hash ํด๋ž˜์Šค๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ƒ์œ„ ์œ ํ˜•์„ HashCode ํ•˜๊ณ  ๊ตฌ์กฐ์ฒด๋ฅผ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด API์˜ "์ง„์ž…์ "์„ ํ•˜๋‚˜์˜ ์ตœ์ƒ์œ„ ์œ ํ˜•์œผ๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ์›ํ•˜๋Š” ์‚ฌ์šฉ์„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

``` C#
๋„ค์ž„์ŠคํŽ˜์ด์Šค ์‹œ์Šคํ…œ
{
๊ณต๊ฐœ ์ •์  ํด๋ž˜์Šค HashCode
{
๊ณต๊ฐœ ์ •์  HashCodeValue ๊ฒฐํ•ฉ(int ํ•ด์‹œ);
๊ณต๊ฐœ ์ •์  HashCodeValue ๊ฒฐํ•ฉ(T obj);
๊ณต๊ฐœ ์ •์  HashCodeValue ๊ฒฐํ•ฉ(T obj, IEqualityComparer๋น„๊ต์ž);

    public struct HashCodeValue : IEquatable<HashCodeValue>
    {
        public HashCodeValue Combine(int hash);
        public HashCodeValue Combine<T>(T obj);
        public HashCodeValue Combine<T>(T obj, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCodeValue hashCode);

        public static bool operator ==(HashCodeValue left, HashCodeValue right);
        public static bool operator !=(HashCodeValue left, HashCodeValue right);

        public bool Equals(HashCodeValue other);
        public override bool Equals(object obj);
        public override int GetHashCode();
    }
}

}
```

ํŽธ์ง‘: HashCodeValue.Value ๊ฐ€ ์•ฝ๊ฐ„ ์ค‘๋ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์ฒฉ ์œ ํ˜•์— ๋Œ€ํ•ด HashCodeValue ๋ณด๋‹ค ๋” ๋‚˜์€ ์ด๋ฆ„์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Value ๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ž์ฃผ. ์–ด์ฉŒ๋ฉด ์šฐ๋ฆฌ๋Š” ์‹ฌ์ง€์–ด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค Value ์†์„ฑ์„ - ๋‹น์‹ ์ด ์–ป์„ ์ˆ˜์žˆ๋Š” Value ๋ฅผ ํ†ตํ•ด GetHashCode() ๋‹น์‹ ์„ ์บ์ŠคํŒ…ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด int .

@justinvp ํ•˜์ง€๋งŒ ์ฒ˜์Œ์— ๋‘ ๊ฐœ์˜ ๊ฐœ๋ณ„ ์œ ํ˜•์„ ๊ฐ–๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด ์‹œ์Šคํ…œ์€ ์˜ˆ๋ฅผ ๋“ค์–ด LinkedList<T> ๋ฐ LinkedListNode<T> ์— ๋Œ€ํ•ด ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ฒ˜์Œ์— ๋‘ ๊ฐœ์˜ ๋ณ„๋„ ์œ ํ˜•์„ ๊ฐ–๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‘ ๊ฐ€์ง€ ์ตœ์ƒ์œ„ ์œ ํ˜•์—๋Š” ๋‘ ๊ฐ€์ง€ ์šฐ๋ ค ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. API์˜ "์ง„์ž…์ " ์œ ํ˜•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๋ฆ„์ด Hash ๋ฐ HashCode ๊ฒฝ์šฐ ์–ด๋Š ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ ์ด๋ฆ„์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. LinkedList<T> ๋ฐ LinkedListNode<T> ํ•˜๋ฉด ์–ด๋Š ๊ฒƒ์ด ์ฃผ์š” ์ง„์ž…์  LinkedList<T> ์ด๊ณ  ์–ด๋Š ๊ฒƒ์ด ๋„์šฐ๋ฏธ์ธ์ง€ ๋งค์šฐ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.
  2. System ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์˜ค์—ผ์‹œํ‚ต๋‹ˆ๋‹ค. (1)๋งŒํผ ์šฐ๋ คํ•  ์‚ฌํ•ญ์€ ์•„๋‹ˆ์ง€๋งŒ System ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ๋•Œ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•  ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

์ค‘์ฒฉ์€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

@justinvp

API์˜ "์ง„์ž…์ " ์œ ํ˜•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๋ฆ„์ด Hash์™€ HashCode๋ผ๋ฉด ์–ด๋–ค ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๊ทธ ์ด๋ฆ„์—์„œ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. LinkedList ์‚ฌ์šฉ๋ฐ LinkedListNode์–ด๋Š ๊ฒƒ์ด ์ฃผ์š” ์ง„์ž…์ ์ธ LinkedList์ธ์ง€๋Š” ๋งค์šฐ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค., ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ๋„์šฐ๋ฏธ์ž…๋‹ˆ๋‹ค.

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ถฉ๋ถ„ํ•œ ์ง€์ ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ ์œ ํ˜•์ด ์•„๋‹Œ Hash ๋ฐ HashValue ์œ ํ˜•์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๊ทธ๊ฒƒ์€ ๋‘ ์œ ํ˜• ์‚ฌ์ด์˜ ์ข…์†์ ์ธ ๊ด€๊ณ„๋ฅผ ์ถฉ๋ถ„ํžˆ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ?

๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ง‘๋‹ˆ๋‹ค. Hash.Combine(field1).Combine(field2) . ๋˜ํ•œ ๊ตฌ์กฐ์ฒด ์œ ํ˜• ์ž์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์‹ค์šฉ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ˆ„๊ตฐ๊ฐ€ ํ•ด์‹œ ๋ชฉ๋ก์„ ์ˆ˜์ง‘ํ•˜๊ณ  ์ด๋ฅผ ๋…์ž์—๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด List<int> ๋Œ€์‹  List<HashValue> ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ ์œ ํ˜•์„ List<HashCode.HashCodeValue> ๋กœ ๋งŒ๋“  ๊ฒฝ์šฐ์—๋Š” ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค( List<Hash.Value> ๋„ ์–ธ๋œป ๋ณด๊ธฐ์—๋Š” ๋‹ค์†Œ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค).

์‹œ์Šคํ…œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์˜ค์—ผ์‹œํ‚ต๋‹ˆ๋‹ค. (1)๋งŒํผ ์šฐ๋ คํ•  ์‚ฌํ•ญ์€ ์•„๋‹ˆ์ง€๋งŒ System ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ๋•Œ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•  ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ๊ด€๋ก€๋ฅผ ๋”ฐ๋ฅด๊ณ  ์‚ฌ์šฉ ํŽธ์˜์„ฑ์„ ํฌ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ค‘์ฒฉ ์œ ํ˜•์ด ์žˆ๋Š” ๊ณณ์—์„œ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ BCL API(๋ถˆ๋ณ€ ์ปฌ๋ ‰์…˜์€ ํฌํ•จ๋˜์ง€ ์•Š์œผ๋ฉฐ ์—„๊ฒฉํ•˜๊ฒŒ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹˜)๋Š” ์ค‘์ฒฉ๋œ ์œ ํ˜•์„ ์ ๊ทน์ ์œผ๋กœ ์ˆจ๊ธฐ๋ ค๋Š” List<T>.Enumerator . ์ปดํŒŒ์ผ๋Ÿฌ ์‚ฌ์šฉ์„ ์œ„ํ•œ ํ˜•์‹์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Value ์†์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. int๋กœ ๋ณ€ํ™˜ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด GetHashCode()๋ฅผ ํ†ตํ•ด Value๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋” ์ผ์ฐ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๋Š” ์œ ํ˜•์ด GetHashCode ์žฌ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์•”์‹œ์  ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ œ์•ˆ๋œ API

public static class Hash
{
    public static HashValue Combine(int hash);
    public static HashValue Combine<T>(T obj);
    public static HashValue Combine<T>(T obj, IEqualityComparer<T> comparer);
}

public struct HashValue : IEquatable<HashValue>
{
    public HashValue Combine(int hash);
    public HashValue Combine<T>(T obj);
    public HashValue Combine<T>(T obj, IEqualityComparer<T> comparer);

    public int Value { get; }

    public static implicit operator int(HashValue hashValue);

    public static bool operator ==(HashValue left, HashValue right);
    public static bool operator !=(HashValue left, HashValue right);

    public override bool Equals(object obj);
    public bool Equals(HashValue other);
    public override int GetHashCode();
}

์ค‘์ฒฉ ์œ ํ˜•์ด ์•„๋‹Œ Hash ๋ฐ HashValue ์œ ํ˜•์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

Hash ๋Š” ๋‚˜์—๊ฒŒ ๋„ˆ๋ฌด ์ผ๋ฐ˜์ ์ธ ์ด๋ฆ„์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์ง„์ž…์  API์˜ ์ด๋ฆ„์— HashCode ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋ชฉ์ ์€ GetHash() ์•„๋‹ˆ๋ผ GetHashCode() ๊ตฌํ˜„์„ ๋•๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ํ•ด์‹œ ๋ชฉ๋ก์„ ์ˆ˜์ง‘ํ•˜๊ณ  ์ด๋ฅผ ๋…์ž์—๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๋ชฉ๋ก ๋Œ€์‹  ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.. ์œ ํ˜•์„ ์ค‘์ฒฉํ•˜๋ฉด ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(์‹ฌ์ง€์–ด ๋ชฉ๋ก์–ธ๋œป๋ณด๊ธฐ์—๋Š” ๋‹ค์†Œ ํ˜ผ๋ž€ ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค).

์ด๊ฒƒ์€ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋ฐ•ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋””์ž์ธ์„ ์ตœ์ ํ™”ํ•ด์•ผ ํ•˜๋Š”์ง€ ํ™•์‹ ์ด ์„œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ ์œ ํ˜•์ด ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ BCL API

TimeZoneInfo.AdjustmentRule ๋ฐ TimeZoneInfo.TransitionTime ๋Š” ์˜๋„์ ์œผ๋กœ ์ค‘์ฒฉ ์œ ํ˜•์œผ๋กœ ์ถ”๊ฐ€๋œ BCL์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.

@justinvp

์ง„์ž…์  API์˜ ์ด๋ฆ„์— HashCode๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋ชฉ์ ์€ GetHash()๊ฐ€ ์•„๋‹ˆ๋ผ GetHashCode() ๊ตฌํ˜„์„ ๋•๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๐Ÿ‘ ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ข€ ๋” ์ƒ๊ฐํ•ด ๋ดค์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์€ ์‹ค์ œ ์œ ํ˜•์„ ๋ณด์ง€ ๋ชปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€๋งŒ: ์œ ํ˜•์„ HashCodeValue ๋Œ€์‹  Seed ๋ผ๊ณ  ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„์˜ ์ปจํ…์ŠคํŠธ๋Š” ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค์— ์ด๋ฏธ ์•”์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ์•ˆ๋œ API

namespace System
{
    public static class HashCode
    {
        public static Seed Combine(int hash);
        public static Seed Combine<T>(T obj);
        public static Seed Combine<T>(T obj, IEqualityComparer<T> comparer);

        public struct Seed : IEquatable<Seed>
        {
            public Seed Combine(int hash);
            public Seed Combine<T>(T obj);
            public Seed Combine<T>(T obj, IEqualityComparer<T> comparer);

            public int Value { get; }

            public static implicit operator int(Seed seed);

            public static bool operator ==(Seed left, Seed right);
            public static bool operator !=(Seed left, Seed right);

            public bool Equals(Seed other);
            public override bool Equals(object obj);
            public override int GetHashCode();
        }
    }
}

@jamesqo ๋Œ€์‹  public readonly int Value ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์ด์˜ ๋˜๋Š” ๊ตฌํ˜„ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? Seed ๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ๊ฒฐํ•ฉ ํ›„ ์‹œ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ @justinvp์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. Hash ๋Š” ํ•ด์‹œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์•ฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ HashCode ๋Œ€์‹  ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

@redknightlois ๋ถ„๋ช…ํžˆ

        public struct Seed : IEquatable<Seed>
        {
            public Seed Combine(int hash);
            public Seed Combine<T>(T obj);
            public Seed Combine<T>(T obj, IEqualityComparer<T> comparer);

            public int Value { get; }

            public static implicit operator int(Seed seed);

            public static bool operator ==(Seed left, Seed right);
            public static bool operator !=(Seed left, Seed right);

            public bool Equals(Seed other);
            public override bool Equals(object obj);
            public override int GetHashCode();
        }

์šฉ๋ฒ•:
c# int hashCode = HashCode.Combine(field1).Combine(name, StringComparison.OrdinalIgnoreCase).Value; int hashCode = (int)HashCode.Combine(field1).Combine(field2);

Seed์˜ ๋ฌธ์ œ๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ๊ฒฐํ•ฉ ํ›„ ์ข…์ž๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ƒˆ๋กœ์šด ์”จ์•—์„ ์ƒ์‚ฐํ•˜๋Š” ๋‹ค์Œ ๊ฒฐํ•ฉ์˜ ์”จ์•—์ž…๋‹ˆ๋‹ค.

๋Œ€์‹  public readonly int Value๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋ฐ˜๋Œ€ ๋˜๋Š” ๊ตฌํ˜„ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์™œ์š”? int Value { get; } ๋Š” ๋ณด๋‹ค ๊ด€์šฉ์ ์ด๋ฉฐ ์‰ฝ๊ฒŒ ์ธ๋ผ์ธ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ์ƒˆ๋กœ์šด ์”จ์•—์„ ์ƒ์‚ฐํ•˜๋Š” ๋‹ค์Œ ๊ฒฐํ•ฉ์˜ ์”จ์•—์ž…๋‹ˆ๋‹ค.

๋ฌ˜๋ชฉ์ด ์•„๋‹ˆ๊ฒ ์Šต๋‹ˆ๊นŒ? ;)

@jamesqo ๋‚ด ๊ฒฝํ—˜์—

ํŽธ์ง‘: ๋˜ํ•œ ํ•ด๋‹น ๊ตฌ์กฐ์ฒด๊ฐ€ ์‹ค์ œ๋กœ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์•„์ด๋””์–ด๋„ ์ถ”์ง„ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋ณต์žกํ•œ ์ฝ”๋“œ ์†์„ฑ์œผ๋กœ ๋‘˜๋Ÿฌ์‹ธ์—ฌ ์žˆ์œผ๋ฉด ํ•„๋“œ๋ณด๋‹ค ๋” ๋‚˜์œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค(๊ทธ ์ค‘์—์„œ ์ธ๋ผ์ธ์ด ์•„๋‹˜).

์ž๋™ ๊ตฌํ˜„ ์†์„ฑ์ด ํ•ญ์ƒ ์ธ๋ผ์ธ๋˜์ง€ ์•Š๋Š” ๋‹จ์ผ ๋น„ ๋””๋ฒ„๊ทธ ๋นŒ๋“œ๋ฅผ ์ฐพ์œผ๋ฉด ์ด๋Š” JIT ๋ฌธ์ œ์ด๋ฉฐ ํ™•์‹คํžˆ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ตฌ์กฐ์ฒด์— ์žˆ๋Š” ๋‹จ์ผ int์˜ ์ฝ๊ธฐ ์ „์šฉ ํ•„๋“œ๋Š” ๋ ˆ์ง€์Šคํ„ฐ์—์„œ ๋ฐ”๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

์ฝ๊ธฐ ์ „์šฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ—ˆ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ตœ์ ํ™”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ตฌ์กฐ์ฒด์˜ ์ง€์› ํ•„๋“œ๋Š” ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค. API๋Š” ์ ‘๊ทผ์ž๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@jamesqo ์ฐพ์œผ๋ฉด ๋ช…์‹ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ ๊ทธ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ด ์‹œ์ ์—์„œ ๊ทผ์œก ๋ฉ”๋ชจ๋ฆฌ).

์ค‘์ฒฉ๋œ ๊ตฌ์กฐ์ฒด๋ฅผ "Seed"๊ฐ€ ์•„๋‹Œ "State"๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@ellismg ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ์ œ์•ˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‚ด๋ถ€ ๊ตฌ์กฐ์ฒด์— ๋Œ€ํ•œ ์ข‹์€ ์ด๋ฆ„์„ ์ƒ๊ฐํ•ด๋‚ด๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

@karelz ์ด API๋Š” ๋งˆ์นจ๋‚ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ๋ชจ๋“  ๊ฒƒ์ด ์ปดํŒŒ์ผ๋˜๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ์ด์˜๋ฅผ ์ œ๊ธฐํ•˜์ง€ ์•Š๋Š” ํ•œ ์ด์— ๋Œ€ํ•œ ๊ตฌํ˜„ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@jamesqo @JonHanna ์™œ ์šฐ๋ฆฌ๋Š” ํ•„์š” ์•Š์€ Combine<T>(T obj) ๋Œ€์‹  Combine(object o) ?

์ฝค๋ฐ”์ธ์ด ํ•„์š”ํ•œ ์ด์œ Combine(object o) ๋Œ€์‹  (T obj)?

์ธ์Šคํ„ด์Šค๊ฐ€ ๊ตฌ์กฐ์ฒด์ธ ๊ฒฝ์šฐ ํ›„์ž๋Š” ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

์•—, ์„ค๋ช… ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ค‘์ฒฉ ์œ ํ˜•์€ ๋””์ž์ธ์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๋Š” ์ •์  ๋ฐ ๋น„์ •์  ์ด๋ฆ„์„ ๋™์ผํ•˜๊ฒŒ ์ง€์ •ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ •์ ์„ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. Create ์ด๋ฆ„์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„๊ตํ•˜์—ฌ ์ƒ๋‹นํžˆ ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๊ฐ€์žฅ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ•๋ ฅํ•œ ๋ฐ˜๋Œ€๊ฐ€ ์—†๋Š” ํ•œ ์šฐ๋ฆฌ๊ฐ€ ๊ฒฐ์ •ํ•œ ๋””์ž์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

```C#
๋„ค์ž„์ŠคํŽ˜์ด์Šค ์‹œ์Šคํ…œ
{
๊ณต๊ฐœ ๊ตฌ์กฐ์ฒด ํ•ด์‹œ ์ฝ”๋“œ: IEquatable
{
๊ณต๊ฐœ ์ •์  HashCode Create(int hashCode);
๊ณต๊ฐœ ์ •์  HashCode ๋งŒ๋“ค๊ธฐ(T obj);
๊ณต๊ฐœ ์ •์  HashCode ๋งŒ๋“ค๊ธฐ(T obj, IEqualityComparer๋น„๊ต์ž);

    public HashCode Combine(int hashCode);
    public HashCode Combine<T>(T obj);
    public HashCode Combine<T>(T obj, IEqualityComparer<T> comparer);

    public int Value { get; }

    public static implicit operator int(HashCode hashCode);

    public static bool operator ==(HashCode left, HashCode right);
    public static bool operator !=(HashCode left, HashCode right);

    public bool Equals(HashCode other);
    public override bool Equals(object obj);
    public override int GetHashCode();
}

}
```

์Šน์ธ๋œ ์ œ์•ˆ์— ๋Œ€ํ•œ ๊ฐ•๋ ฅํ•œ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ์„ ๋•Œ๊นŒ์ง€ ๋ฉฐ์น ์„ ๊ธฐ๋‹ค๋ ค ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ '์žก๊ธฐ ์œ„ํ•ด' ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋””์ž์ธ์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ์ฝ”๋“œ์—์„œ HashCode.State๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด(์˜ˆ: ๋ณ€์ˆ˜ ์œ ํ˜• ์ •์˜) ๊ทธ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ๋‚˜์ ์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ข…์ข… ๊ทธ๋Ÿด ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๊นŒ? ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ Value๋ฅผ ์™„์ „ํžˆ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ int๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ €๋Š” Create์™€ Combine์˜ ์กฐํ•ฉ์ด ๋” ๋‚˜์˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

https://github.com/dotnet/corefx/issues/8034#issuecomment -262661653์„ ์ฐธ์กฐ

@terrajobst

Create๋กœ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„๊ตํ•˜์—ฌ ์ƒ๋‹นํžˆ ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๊ฐ€์žฅ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ•๋ ฅํ•œ ๋ฐ˜๋Œ€๊ฐ€ ์—†๋Š” ํ•œ ์šฐ๋ฆฌ๊ฐ€ ๊ฒฐ์ •ํ•œ ๋””์ž์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ์ •์  ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ... ๋‚œ ๋‹น์‹ ์„ ๋“ฃ๊ณ ,ํ•˜์ง€๋งŒ ๋‚œ ๊ตฌํ˜„ ์ž‘์—…์„ํ•˜๋Š” ๋™์•ˆ ๋งˆ์ง€๋ง‰ ์ˆœ๊ฐ„ ์ƒ๊ฐํ–ˆ๋‹ค Zero / Empty ์— ์†์„ฑ์„ HashCode , ๊ทธ๋Ÿฐ ๋‹ค์Œ ์‚ฌ๋žŒ๋“ค์ด ๊ฑฐ๊ธฐ์—์„œ Combine ์ „ํ™”ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋Ÿฌ๋ฉด ๋ณ„๋„์˜ Combine / Create ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

namespace System
{
    public struct HashCode : IEquatable<HashCode>
    {
        public static HashCode Empty { get; }

        public HashCode Combine(int hashCode);
        public HashCode Combine<T>(T obj);
        public HashCode Combine<T>(T obj, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCode hashCode);

        public static bool operator ==(HashCode left, HashCode right);
        public static bool operator !=(HashCode left, HashCode right);

        public bool Equals(HashCode other);
        public override bool Equals(object obj);
        public override int GetHashCode();
    }
}

int GetHashCode()
{
    return HashCode.Empty
        .Combine(_1)
        .Combine(_2);
}

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ด๊ฒƒ์ด ์ข‹์€ ์ƒ๊ฐ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ? (๊ทธ๋™์•ˆ PR์„ ์ œ์ถœํ•˜๊ณ  ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด PR์—์„œ ๋ณ€๊ฒฝํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.)

@jamesqo , ์ €๋Š” Empty/Zero ์•„์ด๋””์–ด๋ฅผ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์œผ๋กœ ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค ( Empty ๋Œ€ Create ๊ณต์žฅ ์‚ฌ์ด์— ๊ฐ•ํ•œ ์„ ํ˜ธ๋„๊ฐ€ ์—†์Œ) ... @weshaggard @bartonjs @stephentoub @terrajobst ์—ฌ๋Ÿฌ๋ถ„์€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”?

์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ Create()๊ฐ€ ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฐ™์€ HashCode.Empty ๋ณด๋‹ค new HashCode() .

operator-new๊ฐ€ ์—†๋Š” ๋ฒ„์ „์„ ํ—ˆ์šฉํ•˜๊ณ  ๋‚˜์ค‘์— Create๋ฅผ ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํผ๋กœ ์ •๋ง๋กœ ์›ํ•œ๋‹ค๋Š” ๊ฒฐ์ •์„ ๋ฐฐ์ œํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—... ::shrug::.

์ด๊ฒƒ์ด ๋‚ด ๋ฐ˜๋ฐœ์˜ ์ „์ฒด ๋ฒ”์œ„์ž…๋‹ˆ๋‹ค(๋ณ„๋กœ ๋งŽ์ง€๋Š” ์•Š์Œ).

FWIW Empty / Zero ๋Œ€์‹  Create ํˆฌํ‘œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์„ Empty / Zero ์ค‘๋‹จํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์‹ค์ œ ๊ฐ’์œผ๋กœ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ถ„์ด ์ด์ƒํ•˜๋‹ค/์ด์ƒํ•ด ๋ณด์ธ๋‹ค.

๊ทธ๊ฒƒ์€ ๋˜ํ•œ ๊ฐ€๋‚œํ•œ ์ข…์ž ๊ฒฝํ–ฅ์ด ์žˆ๋Š” 0์œผ๋กœ ํŒŒ์ข…ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋‚™๋‹ด์‹œํ‚ต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋น„์–ด์žˆ๋Š” ๊ฒƒ๋ณด๋‹ค ๋งŒ๋“ค๊ธฐ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜๋Š”์ง€ ์˜์•„ํ•ดํ•ฉ๋‹ˆ๋‹ค. ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์ถ”๊ฐ€ ๊ฐ’์„ ํ˜ผํ•ฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ ์ ‘๊ทผ ๋ฐฉ์‹๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ Empty๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ(๊ทธ๋ฆฌ๊ณ  ์ด๋ฏธ ๋งํ•œ ๋ฐ” ์žˆ์Œ), ์„ธ ๋ฒˆ์งธ ์ƒ๊ฐ ํ›„์— ๋‚˜๋Š” ์—ฌ์ „ํžˆ ๊ทธ๊ฒƒ์ด ๋‚˜์œ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋”์™€ ๊ฐ™์€ ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ์—ฌ์ „ํžˆ 0์„ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ๋‹จ์–ด๋Š” ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@JonHanna ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด: Create ๋Œ€ํ•œ ํˆฌํ‘œ๋ฅผ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๊นŒ?

๊ทธ๋ฆฌ๊ณ  ๋„ค ๋ฒˆ์งธ๋Š” Create ๋Œ€์‹  With์— ๋Œ€ํ•ด ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

HashCode.With(a).Combine(b). ๊ฒฐํ•ฉ(c)

์ตœ์‹  ํ† ๋ก ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์‚ฌ์šฉ ์˜ˆ( Create ๊ฐ€ ๋Œ€์ฒด ์ด๋ฆ„์œผ๋กœ ๋Œ€์ฒด๋  ์ˆ˜ ์žˆ์Œ):

```c#
๊ณต๊ฐœ ์žฌ์ •์˜ int GetHashCode() =>
HashCode.Create(_field1).Combine(_field2).Combine(_field3);

We went down the path of this chaining approach, but didn't reconsider earlier proposals when the static & instance `Combine` methods didn't pan out...

Are we sure we don't want something like the existing `Path.Combine` pattern, that was proposed previously, with a handful of generic `Combine` overloads? e.g.:

```c#
public override int GetHashCode() =>
    HashCode.Combine(_field1, _field2, _field3);

@justinvp ์ผ๊ด€์„ฑ ์—†๋Š” ์ฝ”๋“œ + ๋” ๋งŽ์€ ์ง€ํŒ…์œผ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์ผ๋ฐ˜์ ์ธ ์กฐํ•ฉ์œผ๋กœ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•œ ๊ฒƒ์œผ๋กœ ํŒ๋ช…๋˜๋ฉด ์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ๋‹ค๋ฅธ ๋ฌธ์ œ์—์„œ ์ด๊ฒƒ์„ ๋‹ค์‹œ ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์†Œํ•œ ์‚ฌ์šฉ๋ฒ•์—์„œ๋Š” ์›๋ž˜ ์ œ์•ˆ๋œ ๋ฒ„์ „์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค(์ฝ”๋“œ ํฌ๊ธฐ, ์ง€ํŒ… ๋“ฑ์— ๊ด€ํ•œ ์ฃผ์„์€ ํ™•์‹คํ•˜์ง€ ์•Š์Œ). ๋‹ค๋ฅธ arity์˜ ๋ช‡ ๊ฐ€์ง€ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๋Š” ๋ฌด์–ธ๊ฐ€์— ๋Œ€ํ•ด ์ถ”๊ฐ€ ๊ตฌ์กฐ์™€ 10๊ฐœ ์ด์ƒ์˜ ๋‹ค๋ฅธ ๋ฉค๋ฒ„๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ๊ณผ์ž‰์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ์ฐฝํ•œ ์Šคํƒ€์ผ API์˜ ํŒฌ์ด ์•„๋‹ˆ๋ฏ€๋กœ ์•„๋งˆ๋„ ๊ทธ๊ฒƒ์ด ๋‚ด ์˜๊ฒฌ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์กฐ๊ธˆ ์ด์ƒํ•˜๊ณ  ์•„์ง ๋‚ด ๊ธฐ๋ถ„์ด ์–ด๋–ค์ง€ ํ™•์‹ ์ด ์„œ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์— ๋‹ค๋ฅธ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋Œ€์•ˆ์ด ๊ณ ๋ ค๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค...

์œ ์‚ฌํ•œ Add ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ASP.NET Core์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ HashCodeCombiner "๋นŒ๋”" ๋ผ์ธ์„ ๋”ฐ๋ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ ์ปฌ๋ ‰์…˜ ์ด๋‹ˆ์…œ๋ผ์ด์ € ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ์ง€์›๋„ ํฌํ•จํ–ˆ๋‹ค๋ฉด?

์šฉ๋ฒ•:

```c#
๊ณต๊ฐœ ์žฌ์ •์˜ int GetHashCode() =>
์ƒˆ๋กœ์šด ํ•ด์‹œ ์ฝ”๋“œ { _field1, _field2, _field3 };

With a surface area something like:

```c#
namespace System
{
    public struct HashCode : IEquatable<HashCode>, IEnumerable
    {
        public void Add(int hashCode);
        public void Add<T>(T obj);
        public void Add<T>(T obj, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCode hashCode);

        public static bool operator ==(HashCode left, HashCode right);
        public static bool operator !=(HashCode left, HashCode right);

        public bool Equals(HashCode other);
        public override bool Equals(object obj);
        public override int GetHashCode();

        IEnumerator IEnumerable.GetEnumerator();
    }
}

์ปฌ๋ ‰์…˜ ์ด๋‹ˆ์…œ๋ผ์ด์ € ๊ตฌ๋ฌธ์„ ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด ์ตœ์†Œํ•œ ํ•˜๋‚˜์˜ Add ๋ฉ”์„œ๋“œ์™€ ํ•จ๊ป˜ IEnumerable ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. IEnumerable ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜์—ฌ Intellisense์—์„œ ์ˆจ๊ธฐ๊ณ  GetEnumerator ๋Š” NotSupportedException ๋ฅผ ๋˜์ง€๊ฑฐ๋‚˜ ํ•ด์‹œ ์ฝ”๋“œ ๊ฐ’์„ ์—ด๊ฑฐ ๊ฐ€๋Šฅํ•œ ๋‹จ์ผ ๊ฒฐํ•ฉ ํ•ญ๋ชฉ์œผ๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค (๋“œ๋ฌธ ์ผ์ž…๋‹ˆ๋‹ค).

@justinvp , ํฅ๋ฏธ๋กœ์šด ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์ •์ค‘ํ•˜๊ฒŒ ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. HashCode ๋Š” ๊ฐ€๋ณ€ ๊ตฌ์กฐ์ฒด๊ฐ€ ์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ถˆ๋ณ€์œผ๋กœ ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด๋ฅผ ์œ„ํ•ด IEnumerable ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์†Œ ์ธ๊ณต์ ์ด๊ฑฐ๋‚˜ ๋ถˆ์•ˆ์ •ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ํŒŒ์ผ์— using System.Linq ์ง€์‹œ๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ HashCode ์˜†์— ์ ์„ ๋„ฃ์œผ๋ฉด Cast<> ๋ฐ OfType<> ๊ฐ€ ํ™•์žฅ ๋ฉ”์„œ๋“œ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ˜„์žฌ ์ œ์•ˆ์— ๋” ๊ฐ€๊นŒ์ด ๋‹ค๊ฐ€๊ฐ€์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@jamesqo , ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์กฐ์ฐจ ์ฃผ์ €ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ข‹์•„ํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ์‚ฌ์šฉ๋ฒ•์ด ์ฒด์ธ๋ณด๋‹ค ๊นจ๋—ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ปฌ๋ ‰์…˜ ์ด๋‹ˆ์…œ๋ผ์ด์ €๊ฐ€ ์ƒ˜ํ”Œ ์‚ฌ์šฉ๋ฒ•์„ ๋ณด์ง€ ์•Š๊ณ ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ์ž์ฒด๊ฐ€ ๋˜ ๋‹ค๋ฅธ ๋‹จ์ ์ž…๋‹ˆ๋‹ค.

@MadsTorgersen , @jaredpar , ์ปฌ๋ ‰์…˜ ์ด๋‹ˆ์…œ๋ผ์ด์ €์— IEnumerable ๊ตฌํ˜„์ด ํ•„์š”ํ•œ ์ด์œ \์œ„์˜ @justinvp์˜ ์„ธ ๋ฒˆ์งธ ์˜๊ฒฌ.

@jamesqo , ๋‚˜๋Š” ์ด๊ฒƒ์„ ๋ถˆ๋ณ€(IEnumerable์ด ์•„๋‹Œ)์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

@mellinoe ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ๋ฅผ ์•ฝ๊ฐ„ ๋” ๋‹จ์ˆœํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ, ๊ทธ ์ด์ƒ์„ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ํฌํ•จ:

  1. ์˜ค๋ฒ„๋กœ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ํ•ญ๋ชฉ
  2. ์ •ํ™ฉ
  3. ๋ฃจํ”„
  4. ๋น„๊ต์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ

์ด ์ฃผ์ œ์— ๋Œ€ํ•ด ์ด์ „์— ๊ฒŒ์‹œ๋œ ASP.NET์˜ ์ฝ”๋“œ๋ฅผ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค(ํ˜„์žฌ ์ œ์•ˆ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋จ).

```c#
var ํ•ด์‹œ ์ฝ”๋“œ = ํ•ด์‹œ ์ฝ”๋“œ
.Create(IsMainPage)
.Combine(ViewName, StringComparer.Ordinal)
.Combine(์ปจํŠธ๋กค๋Ÿฌ ์ด๋ฆ„, StringComparer.Ordinal)
.Combine(์˜์—ญ ์ด๋ฆ„, StringComparer.Ordinal);

if (ViewLocationExpanderValues โ€‹โ€‹!= null)
{
foreach(ViewLocationExpanderValues์˜ var ํ•ญ๋ชฉ)
{
ํ•ด์‹œ์ฝ”๋“œ = ํ•ด์‹œ์ฝ”๋“œ
.Combine(item.Key, StringComparer.Ordinal)
.Combine(ํ•ญ๋ชฉ.๊ฐ’, StringComparer.Ordinal);
}
}

๋ฐ˜ํ™˜ ํ•ด์‹œ ์ฝ”๋“œ;

How would this look with the original `Hash.CombineHashCodes`? I think it would be:

```c#
var hashCode = Hash.CombineHashCodes(
    IsMainPage,
    StringComparer.Ordinal.GetHashCode(ViewName),
    StringComparer.Ordinal.GetHashCode(ControllerName),
    StringComparer.Ordinal.GetHashCode(AreaName));

if (ViewLocationExpanderValues != null)
{
    foreach (var item in ViewLocationExpanderValues)
    {
        hashCode = Hash.CombineHashCodes(
            hashCode
            StringComparer.Ordinal.GetHashCode(item.Key),
            StringComparer.Ordinal.GetHashCode(item.Value));
    }
}

return hashCode;

์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต์ž๋ฅผ ์œ„ํ•ด GetHashCode() ํ˜ธ์ถœ์„ ๋ฌด์‹œํ•˜๋”๋ผ๋„ hashCode ์˜ ์ด์ „ ๊ฐ’์„ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@KrzysztofCwalina @ericlippert์— ๋”ฐ๋ฅด๋ฉด์˜ ์–ธ์–ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ C #์—์„œ ๋…ธํŠธ 1, ๊ทธ๊ฒƒ์€ ์ปฌ๋ ‰์…˜ ์ด๋‹ˆ์…œ ๋ผ์ด์ €์ด๊ธฐ ๋•Œ๋ฌธ์— (๋‹น์—ฐํžˆ)ํ•˜์ง€ ์—ฐ์‚ฐ์— ๋Œ€ํ•œ ์ˆ˜์ง‘ ์ƒ์„ฑ์„์œ„ํ•œ ๋ฌธ๋ฒ• ์„คํƒ•, (์ด๋ผ๋Š” ๋ฐฉ๋ฒ•์˜ ๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉํ–ˆ๋‹ค ๋  ์šด๋ช…์ด๋‹ค Add ).

1 Google ๋„์„œ์˜ ์ž‘๋™ ๋ฐฉ์‹์œผ๋กœ ์ธํ•ด ํ•ด๋‹น ๋งํฌ๊ฐ€ ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@KrzysztofCwalina , IEnumerable<T> ๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜์ด ์•„๋‹Œ IEnumerable ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

@svick , ์œ„์˜ ์ฒซ ๋ฒˆ์งธ ์˜ˆ์—์„œ ์‚ฌ์†Œํ•œ ๋‹ˆํŠธ: .Combine ๋Œ€ํ•œ ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ์€ ํ˜„์žฌ ์ œ์•ˆ์—์„œ .Create ์ž…๋‹ˆ๋‹ค. ์ค‘์ฒฉ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ.

@svic

๊ทธ๊ฒƒ์€ ๋˜ํ•œ ๊ทธ ์ด์ƒ์˜ ๊ฒƒ์„ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ๋ฌด์—‡์ด ์˜ณ์€ ์ผ์ธ์ง€์— ๋Œ€ํ•ด ๋œ ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค)

๋‘ ๋ฒˆ์งธ ์˜ˆ์ œ๋Š” ์ „์ฒด์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ์˜ˆ์ œ์™€ ๊ฑฐ์˜ ๋‹ค๋ฅด์ง€ ์•Š์œผ๋ฉฐ ๋” ๋ณต์žกํ•œ IMO๋„ ์•„๋‹™๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ/์›๋ž˜ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งŽ์€ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค(์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” ์‹ค์ œ๋กœ IsMainPage.GetHashCode() ์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค). ๊ทธ๋ž˜์„œ ๋‚˜์—๊ฒŒ๋Š” ๊ฐ„๋‹จํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ œ๊ฐ€ ์†Œ์ˆ˜์— ์†ํ•˜๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ์›๋ž˜์˜ ๋ฐฉ์‹์„ ๊ณ ์ง‘ํ•˜์ง€๋Š” ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฐ•ํ•œ ์˜๊ฒฌ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ๊ฐ€์ง€ ์˜ˆ๋Š” ๋ชจ๋‘ ๋‚˜์—๊ฒŒ ์ถฉ๋ถ„ํžˆ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

@justinvp ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (๋‚˜๋Š” ์ฒซ ๋ฒˆ์งธ ๊ฒŒ์‹œ๋ฌผ์˜ ์ฒซ ๋ฒˆ์งธ ์ œ์•ˆ์œผ๋กœ ๊ฐ”๊ณ  ๊ทธ๊ฒƒ์ด ๊ตฌ์‹์ด๋ผ๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

@mellinoe ๋ฌธ์ œ๋Š” ์‹ค์ œ๋กœ ๋‘ ๋ฒˆ์งธ๊ฐ€ ๋ฏธ๋ฌ˜ํ•œ ๋ฒ„๊ทธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ ์ค‘ ํ•˜๋‚˜์˜ ์‹ค์ œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int GetHashCode(PageFromScratchBuffer obj)
        {
            int v = Hashing.Combine(obj.NumberOfPages, obj.ScratchFileNumber);
            int w = Hashing.Combine(obj.Size.GetHashCode(), obj.PositionInScratchBuffer.GetHashCode());
            return Hashing.Combine(v, w);            
        }

์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๊ณผ ํ•จ๊ป˜ ์‚ด๊ณ  ์žˆ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๋งค์ผ ๋งค์šฐ ๋‚ฎ์€ ์ˆ˜์ค€์˜ ๊ฒƒ๋“ค์„ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ™•์‹คํ•œ ํ‰๊ท  ๊ฐœ๋ฐœ์ž๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์—์„œ v์™€ w๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด v์™€ w๋ณด๋‹ค ... v์™€ w ๊ฒฐํ•ฉ ์‚ฌ์ด์—์„œ ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ด์‹œ ์กฐํ•ฉ์€ ๊ตํ™˜ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฐจ๋ก€๋กœ ์—ฐ๊ฒฐํ•˜๋ฉด ์‹ค์ œ๋กœ API ์ˆ˜์ค€์—์„œ ์ „์ฒด ์˜ค๋ฅ˜ ์ง‘ํ•ฉ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ฒซ ๋ฒˆ์งธ ๊ฒŒ์‹œ๋ฌผ์˜ ์ฒซ ๋ฒˆ์งธ ์ œ์•ˆ์œผ๋กœ ๊ฐ”๊ณ  ๊ทธ๊ฒƒ์ด ๊ตฌ์‹์ด๋ผ๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์™„๋ฃŒ.
BTW: ์ด ์ œ์•ˆ์€ ํŠนํžˆ ํˆฌํ‘œ๋ฅผ ์ถ”์ ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค... ๋„ˆ๋ฌด ๋งŽ์€ ๋ณ€ํ˜•(์ข‹์€ ๊ฒƒ ๊ฐ™์•„์š” ;-))

@karelz Create API๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด Empty ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. @bartonjs๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ๋‘˜ ์ค‘ ํ•˜๋‚˜์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ œ์•ˆ

namespace System
{
    public struct HashCode : IEquatable<HashCode>
    {
        public HashCode();

        public static HashCode Empty { get; }

        public static HashCode Create(int hashCode);
        public static HashCode Create<T>(T value);
        public static HashCode Create<T>(T value, IEqualityComparer<T> comparer);

        public HashCode Combine(int hashCode);
        public HashCode Combine<T>(T value);
        public HashCode Combine<T>(T value, IEqualityComparer<T> comparer);

        public int Value { get; }

        public static implicit operator int(HashCode hashCode);

        public static bool operator ==(HashCode left, HashCode right);
        public static bool operator !=(HashCode left, HashCode right);

        public bool Equals(HashCode other);
        public override bool Equals(object obj);
        public override int GetHashCode();
        public override string ToString();
    }
}

@JonHanna

๊ทธ๊ฒƒ์€ ๋˜ํ•œ ๊ฐ€๋‚œํ•œ ์ข…์ž ๊ฒฝํ–ฅ์ด ์žˆ๋Š” 0์œผ๋กœ ํŒŒ์ข…ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋‚™๋‹ด์‹œํ‚ต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์„ ํƒํ•˜๋Š” ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์˜ค๋Š˜๋‚  HashHelpers ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋ฉฐ hash(0, x) == x ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. HashCode.Empty.Combine(x) ๋Š” HashCode.Create(x) ์™€ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๊ฐ๊ด€์ ์œผ๋กœ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

@jamesqo ๋งˆ์ง€๋ง‰ ์ œ์•ˆ์— ์ถ”๊ฐ€ Zero ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ˆ„๋ฝ์ด๋ผ๋ฉด ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฐ ๋‹ค์Œ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ตœ์‹  ์ œ์•ˆ์— ํˆฌํ‘œํ•˜๋„๋ก ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋Œ€์•ˆ(๋‚ด๊ฐ€ ์—…๋ฐ์ดํŠธํ•œ ์ƒ์œ„ ๊ฒŒ์‹œ๋ฌผ ์ฐธ์กฐ)์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŽ์ด ์–ป์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ...

@karelz ์ฐพ์•„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

@KrzysztofCwalina ๋Š” ๋‹ค๋ฅธ ์˜๋ฏธ๊ฐ€ ์•„๋‹ˆ๋ผ ์ปฌ๋ ‰์…˜์— ์ถ”๊ฐ€ํ•œ๋‹ค๋Š” ์˜๋ฏธ์—์„œ "์ถ”๊ฐ€"๋ฅผ ์˜๋ฏธํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ด ์ œํ•œ์ด ๋งˆ์Œ์— ๋“œ์…จ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋‹น์‹œ์—๋Š” ๊ทธ๋ ‡๊ฒŒ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

public static HashCode Create(int hash);
public HashCode Combine(int hash);

๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค hashCode ๋Œ€์‹  hash ๋ถ€ํ„ฐ ์ „๋‹ฌ ๋œ ๊ฐ’ ๊ฐ€๋Šฅ์„ฑ์ด ํ˜ธ์ถœ์—์„œ ์–ป์€ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๋  ๊ฒƒ๋ฉ๋‹ˆ๋‹ค GetHashCode() ?

Empty / Zero

์ด๊ฒƒ์„ ์œ ์ง€ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๊ณ ๋ คํ•ด์•ผ ํ•  ๋˜ ๋‹ค๋ฅธ ์ด๋ฆ„์€ Default ์ž…๋‹ˆ๋‹ค.

@justinvp

์ „๋‹ฌ๋œ ๊ฐ’์ด GetHashCode()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์–ป์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ ํ•ด์‹œ ๋Œ€์‹  hashCode๋กœ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

int ๋งค๊ฐœ๋ณ€์ˆ˜ hash ๋ฐ HashCode ๋งค๊ฐœ๋ณ€์ˆ˜ hashCode ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์‹œ ์ƒ๊ฐํ•ด ๋ณด๋ฉด hashCode ๊ฐ€ ๋” ์ข‹์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์–ธ๊ธ‰ํ•œ ๋Œ€๋กœ hash ๊ฐ€ ๋‹ค์†Œ ๋ชจํ˜ธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. API๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์œ ์ง€ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๊ณ ๋ คํ•ด์•ผ ํ•  ๋˜ ๋‹ค๋ฅธ ์ด๋ฆ„์€ Default์ž…๋‹ˆ๋‹ค.

Default ๋“ค์—ˆ์„ ๋•Œ ๋‚˜๋Š” "๊ตฌ์กฐ์ฒด์˜ ๊ธฐ๋ณธ๊ฐ’"์ด ์•„๋‹ˆ๋ผ "์–ด๋–ค ์˜ต์…˜์„ ์„ ํƒํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅผ ๋•Œ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•"์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Encoding.Default ์™€ ๊ฐ™์€ ๊ฒƒ์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์„ ํƒํ•˜๋Š” ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์˜ค๋Š˜๋‚  HashHelpers์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๊ฒƒ์ด๋ฉฐ, ์ด๋Š” hash(0, x) == x์™€ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. HashCode.Empty.Combine(x)๋Š” HashCode.Create(x)์™€ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๊ฐ๊ด€์ ์œผ๋กœ ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์˜ ๋‚ด๋ถ€์— ๋Œ€ํ•ด ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ์œผ๋กœ์„œ ์ €๋Š” HashCode.Create(x).Combine(...) ์˜ ๋‹จ์ˆœํ•จ์ด ์ •๋ง ์ข‹์Šต๋‹ˆ๋‹ค. Create ๋Š” ๋‹ค๋ฅธ ๋งŽ์€ ๊ณณ์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Empty / Zero / Default ๊ฐ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด IMO์— ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ถ”์‹ : ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ์Šค๋ ˆ๋“œ!! ์ž˜ ํ–ˆ์–ด! ๐Ÿ‘

@cwe1ss

Empty / Zero / Default๊ฐ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด IMO์— ์žˆ์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

Empty ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ํ•ด์‹œ๋ฅผ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” "์‹œ์ž‘ ๊ฐ’"์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Create ์‚ฌ์šฉํ•˜์—ฌ ํ•ด์‹œ ๋ฐฐ์—ด์„ ๊ฒฐํ•ฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๋งค์šฐ ๊ณ ํ†ต์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

int CombineRange(int[] hashes)
{
    if (hashes.Length == 0)
    {
        return 0;
    }

    var result = HashCode.Create(hashes[0]);

    for (int i = 1; i < hashes.Length; i++)
    {
        result = result.Combine(hashes[i]);
    }

    return result;
}

Empty ๊ฐ€ ์žˆ์œผ๋ฉด ํ›จ์”ฌ ๋” ์ž์—ฐ์Šค๋Ÿฌ์›Œ์ง‘๋‹ˆ๋‹ค.

int CombineRange(int[] hashes)
{
    var result = HashCode.Empty;

    for (int i = 0; i < hashes.Length; i++)
    {
        result = result.Combine(hashes[i]);
    }

    return result;
}

// or

int CombineRange(int[] hashes)
{
    return hashes.Aggregate(HashCode.Empty, (hc, next) => hc.Combine(next));
}

@terrajobst ์ด ์œ ํ˜•์€ ์ €์—๊ฒŒ ImmutableArray<T> ์™€ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋นˆ ๋ฐฐ์—ด์€ ๊ทธ ์ž์ฒด๋กœ๋Š” ๊ทธ๋‹ค์ง€ ์œ ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ ๋‹ค๋ฅธ ์ž‘์—…์˜ "์‹œ์ž‘์ "์œผ๋กœ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์ด์— ๋Œ€ํ•œ Empty ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. HashCode ์—๋„ ํ•˜๋‚˜๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” Create ํ•ฉ๋‹ˆ๋‹ค.

@jamesqo ๋‚˜๋Š” ๋‹น์‹ ์ด ์ œ์•ˆ์„œ https://github.com/dotnet/corefx/issues/8034#issuecomment -262661653์—์„œ ๋‹น์‹ ์ด ์ž๋™์œผ๋กœ/์‹ค์ˆ˜๋กœ arg name obj ์„ value ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์ฐจ๋ ธ์Šต๋‹ˆ๋‹ค. IMO๊ฐ€ ์–ป๋Š” ๊ฒƒ์„ ๋” ์ž˜ ์บก์ฒ˜ํ•˜๋Š” obj ๋‹ค์‹œ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฆ„ value ๋Š” ์ด ์ปจํ…์ŠคํŠธ์—์„œ "int" ํ•ด์‹œ ๊ฐ’ ์ž์ฒด์™€ ๋” ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•„์š”ํ•œ ๊ฒฝ์šฐ arg ์ด๋ฆ„์— ๋Œ€ํ•ด ์ถ”๊ฐ€ ํ† ๋ก ์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์˜๋„์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์Šน์ธ๋œ ์ œ์•ˆ๊ณผ์˜ ์ฐจ์ด์ ์„ ์ถ”์ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ƒ๋‹จ์˜ ์ œ์•ˆ์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ์ œ์•ˆ์„œ์˜ ๋งˆ์ง€๋ง‰ ์Šน์ธ ๋ฒ„์ „์— ๋Œ€ํ•ด diff๋ฅผ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์„ ํƒํ•˜๋Š” ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์˜ค๋Š˜๋‚  HashHelpers์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ฒฐํ•ฉ๋˜๋Š” ํ•ด์‹œ์ฝ”๋“œ์— ๋Œ€ํ•ด ์–ด๋–ค ๊ฐ€์ •์„ ํ•ฉ๋‹ˆ๊นŒ? ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด DDoS ๊ณต๊ฒฉ์˜ ์ƒˆ๋กœ์šด ๊ธธ์„ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? (๊ณผ๊ฑฐ์— ๋ฌธ์ž์—ด ํ•ด์‹ฑ์œผ๋กœ ์ธํ•ด ํ™”์ƒ์„ ์ž…์—ˆ์Šต๋‹ˆ๋‹ค.)

ASP.NET Core์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ HashCodeCombiner "๋นŒ๋”" ๋ผ์ธ์„ ๋”ฐ๋ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ–ˆ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉํ•œ ํŒจํ„ด์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ ๋ฒ”์šฉ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•ด์‹œ์ฝ”๋“œ ์ž์ฒด์— ๋งž๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋” ํฐ ๊ตฌ์กฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๋Šฅ ๋ฌธ์ œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ฐฝํ•œ ํŒจํ„ด์ด ๋ฌด๋„ˆ์ง‘๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ธ ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. https://github.com/dotnet/corefx/issues/8034#issuecomment -260790829์—์„œ ๋‚ด ์˜๊ฒฌ์„

๊ฒฐํ•ฉ๋˜๋Š” ํ•ด์‹œ์ฝ”๋“œ์— ๋Œ€ํ•ด ์–ด๋–ค ๊ฐ€์ •์„ ํ•ฉ๋‹ˆ๊นŒ? ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด DDoS ๊ณต๊ฒฉ์˜ ์ƒˆ๋กœ์šด ๊ธธ์„ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

ํ˜„์žฌ ํ•ด์‹œ์˜ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๋Š” hash(0, x) == x ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ผ๋ จ์˜ null ๋˜๋Š” 0์ด ํ•ด์‹œ์— ์ž…๋ ฅ๋˜๋ฉด 0์œผ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ null์ด ๊ณ„์‚ฐ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ง์€ ์•„๋‹ˆ์ง€๋งŒ ์ดˆ๊ธฐ null์€ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 0์—์„œ 0์œผ๋กœ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋งˆ๋ฒ• ์ƒ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” here ์™€ ๊ฐ™์ด ๋” ๊ฐ•๋ ฅํ•œ(๊ทธ๋Ÿฌ๋‚˜ ์•ฝ๊ฐ„ ๋” ๋น„์‹ผ) ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉํ•œ ํŒจํ„ด์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ ๋ฒ”์šฉ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•ด์‹œ์ฝ”๋“œ ์ž์ฒด์— ๋งž๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋” ํฐ ๊ตฌ์กฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๋Šฅ ๋ฌธ์ œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ฐฝํ•œ ํŒจํ„ด์ด ๋ฌด๋„ˆ์ง‘๋‹ˆ๋‹ค.

๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•˜๋„๋ก ์‹œ๋„ํ•˜๋Š” ํฐ ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง„ ๋ฒ”์šฉ ๊ฒฐํ•ฉ๊ธฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ชจ๋“  int ํฌ๊ธฐ( FnvHashCode ๋“ฑ)์ด๊ณ  ๋ชจ๋‘ ๊ณ ์œ ํ•œ Combine ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ๋ณ„๋„์˜ ํ•ด์‹œ ์ฝ”๋“œ ์œ ํ˜•์„ ๊ตฌ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ด๋Ÿฌํ•œ "๋นŒ๋”" ์œ ํ˜•์€ ์ „๋‹ฌ๋˜์ง€ ์•Š๊ณ  ์–ด์จŒ๋“  ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•˜๋„๋ก ์‹œ๋„ํ•˜๋Š” ํฐ ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง„ ๋ฒ”์šฉ ๊ฒฐํ•ฉ๊ธฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ASP.NET Core๋Š” ํ˜„์žฌ ์ƒํƒœ๊ฐ€ 64๋น„ํŠธ์ธ ์ž์ฒด ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ ๋ฅผ ์ด๊ฒƒ์œผ๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ชจ๋‘ int ํฌ๊ธฐ(FnvHashCode ๋“ฑ)์ธ ๋ณ„๋„์˜ ํ•ด์‹œ ์ฝ”๋“œ ์œ ํ˜•์„ ๊ตฌ์ƒํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๊ฒฐํ•ฉ ํญ๋ฐœ๋กœ ์ด์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์ด API ๋””์ž์ธ์ด ๋ฌด์—‡์œผ๋กœ ์ด์–ด์ง€๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด API ์ œ์•ˆ์˜ ์ผ๋ถ€์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@jkotas ํ† ๋ก  ์ดˆ๋ฐ˜์— ๋น„์Šทํ•œ ๋ฐ˜๋Œ€ ์˜๊ฒฌ์„ ๋ฐํ˜”์Šต๋‹ˆ๋‹ค. ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฃจ๋ ค๋ฉด ์ฃผ์ œ ์ง€์‹์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 2001๋…„์— ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ฐ€์žฅ ๋ฟŒ๋ฆฌ์— ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋„์ž…ํ•˜์—ฌ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๊ณ  ์ง€์ง€ํ•˜๋ฉฐ ํ•ด์‹œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฒ˜๋ฐฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์„ค๊ณ„๋Š” 99%์˜ ๊ฒฝ์šฐ(ํ•ด์‹œ์˜ ํ†ต๊ณ„์  ์†์„ฑ์ด ์ถฉ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์ œ ์ง€์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜ ํ•„์š”ํ•œ ๊ฒฝ์šฐ)์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ASP.Net Core๋Š” https://github.com/dotnet/corefx/issues/13757 ์—์„œ ๋…ผ์˜๋ฅผ ์œ„ํ•ด ์ œ์•ˆ๋œ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋น„์‹œ์Šคํ…œ ์–ด์…ˆ๋ธ”๋ฆฌ์˜ ๋ฒ”์šฉ ํ”„๋ ˆ์ž„์›Œํฌ์— ์ด๋Ÿฌํ•œ ๊ฒฐํ•ฉ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

99%์˜ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 32๋น„ํŠธ๋ณด๋‹ค ๋” ๋งŽ์€ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ํ—ˆ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

BTW: ASP.NET์€ ์›๋ž˜ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ์— ์œ ์ฐฝํ•œ ํŒจํ„ด์„ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ๋ฒ„๊ทธ๋ฅผ ๋†“์น˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/aspnet/Razor/pull/537

ํ•ด์‹œ ํ”Œ๋Ÿฌ๋”ฉ ๋ณด์•ˆ์— ๊ด€ํ•œ @jkotas .
๋ฉด์ฑ… ์กฐํ•ญ: ์ „๋ฌธ๊ฐ€๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค(ํ•œ ์‚ฌ๋žŒ์—๊ฒŒ ๋ฌธ์˜ํ•ด์•ผ ํ•˜๋ฉฐ MS๋Š” ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ์ด์ƒ์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค) .

๋‚˜๋Š” ์ฃผ๋ณ€์„ ๋‘˜๋Ÿฌ๋ณด์•˜๊ณ  ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ํ•ฉ์˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ์š”์ฆ˜ ์ฃผ๋ชฉ์„ ๋ฐ›๊ณ  ์žˆ๋Š” ์ฃผ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด์‹œ ์ฝ”๋“œ๋Š” 32๋น„ํŠธ ํฌ๊ธฐ์ด๋ฉฐ, ์ง‘ํ•ฉ์˜ ํฌ๊ธฐ๊ฐ€ ์ฃผ์–ด์ง„ ๊ฒฝ์šฐ ์ถฉ๋Œ ํ™•๋ฅ ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ทธ๋ž˜ํ”„ ์•ž์— ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์•„๋ฌด๋ฆฌ ์šฐ์ˆ˜ํ•˜๋”๋ผ๋„(์˜ˆ๋ฅผ ๋“ค์–ด SipHash ์‚ดํŽด๋ณด๊ธฐ) ๋งŽ์€ ํ•ด์‹œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ฉ๋ฆฌ์ ์ธ ์‹œ๊ฐ„(์•ฝ 1์‹œ๊ฐ„ ๋ฏธ๋งŒ)์— ์ถฉ๋Œ์„ ์ฐพ๋Š” ๊ฒƒ์€ ๊ฝค ์‹คํ–‰ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” ํ•ด์‹œ๋ฅผ ๋ณด์œ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋ฉฐ ํ•ด์‹œ ํ•จ์ˆ˜ ์ˆ˜์ค€์—์„œ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ํ•ด์‹œ ํ”Œ๋Ÿฌ๋”ฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋น„์•”ํ˜ธํ™”์—์„œ ์ถ”๊ฐ€ ์„ฑ๋Šฅ์„ ์ง€๋ถˆํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: ๋‹น์‹ ์€ ๋‚ด๊ฐ€ ์“ฐ๋Š” ๋™์•ˆ ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋น„์ถ”์–ด ๋ณผ ๋•Œ 64๋น„ํŠธ ์ƒํƒœ๊ฐ€ ์–ป๋Š” ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@jkotas ๋งํฌํ•˜์‹  ๋ฌธ์ œ๋ฅผ ์กฐ์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋งํ•œ๋‹ค:

aspnet/Common#40์— ๋Œ€ํ•œ ๋ฐ˜์‘

https://github.com/aspnet/Common/issues/40์— ๋Œ€ํ•œ ์„ค๋ช…:

๋ฒ„๊ทธ ๋ฐœ๊ฒฌ:

public class TagBuilder
{
    private Dictionary<string, string> _attributes;
    private string _tagName;
    private string _innerContent;

    public override int GetHashCode()
    {
        var hash = HashCodeCombiner.Start()
            .Add(_tagName, StringComparer.Ordinal)
            .Add(_innerContent, StringComparer.Ordinal);

        foreach (var kvp in _attributes)
        {
            hash.Add(kvp.Key, StringComparer.Ordinal).Add(kvp.Value, StringComparer.Ordinal);
        }

        return hash.Build();
    }
}

์–ด์„œ ํ•ด๋ด์š”. ๊ทธ ์ธ์ˆ˜๋Š” ์‚ฌ๋žŒ๋“ค์ด Substring ๊ฐ€ ์ƒˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— string ๊ฐ€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ์ฒด๋Š” ๋ฌธ์ œ ์ธก๋ฉด์—์„œ ํ›จ์”ฌ ๋” ๋‚˜์ฉ๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ฒด๋ฅผ ๋ถˆ๋ณ€์œผ๋กœ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•ด์‹œ ํ”Œ๋Ÿฌ๋”ฉ ๋ณด์•ˆ์— ๋Œ€ํ•ด.

์—ฌ๊ธฐ์—๋Š” ๋‘ ๊ฐ€์ง€ ์ธก๋ฉด์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ๊ตฌ์„ฑ ์„ค๊ณ„(๊ฐ•๋ ฅํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋“ฑ); ๋ฐ ๊ธฐ์กด ์„ค๊ณ„์˜ ๋ฌธ์ œ ์™„ํ™”. ๋‘˜ ๋‹ค ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

@karelz ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„ ์ง€์ • ๊ด€๋ จ

๋‚˜๋Š” ๋‹น์‹ ์ด ์ž๋™์œผ๋กœ/์‹ค์ˆ˜๋กœ ๋‹น์‹ ์˜ ์ œ์•ˆ dotnet/corefx#8034(comment)์—์„œ arg name obj๋ฅผ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„์ฐจ๋ ธ์Šต๋‹ˆ๋‹ค. IMO๊ฐ€ ์–ป๋Š” ๊ฒƒ์„ ๋” ์ž˜ ์บก์ฒ˜ํ•˜๋Š” obj๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ปจํ…์ŠคํŠธ์—์„œ ์ด๋ฆ„ ๊ฐ’์€ "int" ํ•ด์‹œ ๊ฐ’ ์ž์ฒด์™€ ๋” ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•„์š”ํ•œ ๊ฒฝ์šฐ arg ์ด๋ฆ„์— ๋Œ€ํ•ด ์ถ”๊ฐ€ ํ† ๋ก ์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์˜๋„์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์Šน์ธ๋œ ์ œ์•ˆ๊ณผ์˜ ์ฐจ์ด์ ์„ ์ถ”์ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ–ฅํ›„ ์ œ์•ˆ์—์„œ API๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ’์„ ์ผ๊ด„์ ์œผ๋กœ ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: CombineRange(ReadOnlySpan<T>) . ์ด ์ด๋ฆ„์„ obj ๋กœ ์ง€์ •ํ–ˆ๋‹ค๋ฉด ๊ฑฐ๊ธฐ์— ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ objs ๋กœ ์ง€์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋งค์šฐ ์–ด์ƒ‰ํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฆ„์„ item ํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋Š” ์ŠคํŒฌ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ items ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ์•ˆ์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

@jkotas ๋Š” ๋™์˜ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ์š”์ ์€ ๊ฒฐํ•ฉ๊ธฐ ์ˆ˜์ค€์—์„œ ์–ด๋–ค ๊ฒƒ๋„ ์™„ํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค...

์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์ผ์€ ์ž„์˜์˜ ์‹œ๋“œ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ƒํƒœ์™€ ๋ชฉ์ ์— ๋Œ€ํ•ด string ์—์„œ ์ฝ”๋“œ๋ฅผ ๋ณธ ๊ฒƒ์„ ๊ธฐ์–ตํ•˜๋ฉฐ ๋นŒ๋“œ๋‹น ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค. (์˜ค๋ž˜์ „ ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ‹€๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.) ๋ฌด์ž‘์œ„ ์‹œ๋“œ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์—ฌ๊ธฐ์— ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์™„ํ™” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋„์ „์ž…๋‹ˆ๋‹ค. ๊ณ ์ •๋œ ์ž„์˜์˜ ์‹œ๋“œ๊ฐ€ ์žˆ๋Š” ์ตœ๊ณ ์˜ ๋ฌธ์ž์—ด ๋ฐ/๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋ฉด ์ถฉ๋Œ๋งŒ ์ƒ์„ฑํ•˜๋Š” 32๋น„ํŠธ ํ•ด์‹œ ์ฝ”๋“œ ์„ธํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฝค ํ•˜๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋Ÿฐ ๋„์ „์„ ํ•˜๋Š” ๊ฒƒ์„ ๋‘๋ ค์›Œํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ™•๋ฅ  ์ด๋ก ์€ ๋‚ด ํŽธ์ด๋‹ค. ๋‚˜๋Š” ์‹ฌ์ง€์–ด ๊ฐ€์„œ ๋‚ด๊ธฐ๋ฅผ ํ•  ๊ฒƒ์ด์ง€๋งŒ ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ด๊ธธ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ณธ์งˆ์ ์œผ๋กœ ๋” ์ด์ƒ ๋‚ด๊ธฐ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€... ๋” ๊นŠ์€ ๋ถ„์„์€ ์™„ํ™”๊ฐ€ ์‹คํ–‰๋‹น ๋‚ด์žฅ๋œ "์ž„์˜์˜ ์‹œ๋“œ"๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์ด๋ผ๊ณ  ํ•ด๋„ ๋” ๋ณต์žกํ•œ ๊ฒฐํ•ฉ๊ธฐ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ์†Œ์Šค์—์„œ ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

M1 ๋ฐ M2 ์žˆ๊ณ  ๋‹ค๋ฅธ ์ž„์˜ ์‹œ๋“œ rs1 ๋ฐ rs2 ....
M1 ๋Š” h1 = hash('a', rs1) ๋ฐ h2=hash('b', rs1) ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค.
M2 ๋Š” h1' = hash('a', rs2) ๋ฐ h2'=hash('b', rs2) ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์„œ ์š”์ ์€ h1 ๋ฐ h1' ๊ฐ€ 1/ (int.MaxInt-1) ( hash ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ข‹์€ ๊ฒฝ์šฐ)์˜ ํ™•๋ฅ ๋กœ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์–ป์„๋งŒํผ ์ข‹์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ c(x,y) ๋ฌด์—‡์ด๋“ (์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ) ์†Œ์Šค์— ๋‚ด์žฅ๋œ ์™„ํ™” ๊ธฐ๋Šฅ์„ ์ด๋ฏธ ๊ณ ๋ คํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: ์ฝ”๋“œ๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ฐ ๋„๋ฉ”์ธ์—์„œ ๋ณ€๊ฒฝ๋˜๋Š” Marvin32๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ์™„ํ™”๋Š” ์‹คํ–‰๋‹น ์ž„์˜์˜ ์‹œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ์ถฉ๋ถ„ํžˆ ์™„ํ™”๋ฉ๋‹ˆ๋‹ค.

@jkotas

ASP.NET Core๋Š” ํ˜„์žฌ ์ƒํƒœ๊ฐ€ 64๋น„ํŠธ์ธ ์ž์ฒด ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋ฅผ ์ด๊ฒƒ์œผ๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ „์ ์œผ๋กœ; ๋™์ผํ•œ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐฉ๊ธˆ ์ด ํ…Œ์ŠคํŠธ ์•ฑ ์„ ๋งŒ๋“ค์–ด ์ถฉ๋Œ ํšŸ์ˆ˜๋ฅผ ์ธก์ •ํ•˜๊ณ  10๋ฒˆ ์‹คํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. 64๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ํฐ ์ฐจ์ด๋Š” ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘ int ํฌ๊ธฐ(FnvHashCode ๋“ฑ)์ธ ๋ณ„๋„์˜ ํ•ด์‹œ ์ฝ”๋“œ ์œ ํ˜•์„ ๊ตฌ์ƒํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๊ฒฐํ•ฉ ํญ๋ฐœ๋กœ ์ด์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์ด API ๋””์ž์ธ์ด ๋ฌด์—‡์œผ๋กœ ์ด์–ด์ง€๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด API ์ œ์•ˆ์˜ ์ผ๋ถ€์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@jkotas , ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์˜ ๋””์ž์ธ์€ ๋ฏธ๋ž˜์˜ ํ•ด์‹ฑ API์— ๋Œ€ํ•œ ๋””์ž์ธ์„ ํ™•์ •์ ์œผ๋กœ ์„ค์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋” ๊ณ ๊ธ‰ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ๊ฐ„์ฃผ๋˜์–ด์•ผ ํ•˜๋ฉฐ dotnet/corefx#13757๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์ œ์•ˆ์œผ๋กœ ์ด๋™ํ•ด์•ผ ํ•˜๋ฉฐ ๋‹ค๋ฅธ ์„ค๊ณ„ ๋…ผ์˜๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. GetHashCode ์žฌ์ •์˜์— ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ๋Š” ์ดˆ๋ณด์ž๋ฅผ ์œ„ํ•ด ์ผ๋ฐ˜ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ API๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

99%์˜ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 32๋น„ํŠธ๋ณด๋‹ค ๋” ๋งŽ์€ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ํ—ˆ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

32๋น„ํŠธ๋ณด๋‹ค ๋” ๋งŽ์€ ๋‚ด๋ถ€ ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋Š” ์–ธ์ œ์ž…๋‹ˆ๊นŒ? ํŽธ์ง‘: ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉ์ž ์ •์˜ ํ•ด์‹ฑ ๋…ผ๋ฆฌ๋ฅผ ํ”Œ๋Ÿฌ๊ทธ์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด ๊ณ ๊ธ‰ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ๊ฐ„์ฃผ๋˜์–ด์•ผ ํ•˜๊ณ  dotnet/corefx#13757์—์„œ ๋…ผ์˜ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๊ฐ ๋„๋ฉ”์ธ์—์„œ ๋ณ€๊ฒฝ๋˜๋Š” Marvin32๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋งž์Šต๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด ํ•ด์‹œ์ฝ”๋“œ ๋ฌด์ž‘์œ„ํ™” ์™„ํ™”๋Š” .NET Core์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜ธํ™˜์„ฑ ๋•Œ๋ฌธ์— ์ „์ฒด .NET Framework์˜ ๋…๋ฆฝ ์‹คํ–‰ํ˜• ์•ฑ์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ ์„ ํ†ตํ•ด์„œ๋งŒ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค(์˜ˆ: ๊ณ ์œ„ํ—˜ ํ™˜๊ฒฝ).

.NET Core์— ๋น„๋ฌด์ž‘์œ„ ํ•ด์‹ฑ์„ ์œ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์—ฌ์ „ํžˆ ์žˆ์ง€๋งŒ ์‚ญ์ œํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ํ•„์š”๋กœ ํ•  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋” ์ด์ƒ ๋ฌด์ž‘์œ„๊ฐ€ ์•„๋‹Œ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด ํ•ด์‹œ์ฝ”๋“œ ๊ณ„์‚ฐ์ด ์กฐ๊ธˆ ๋” ๋นจ๋ผ์ง‘๋‹ˆ๋‹ค.

๋ฌด์ž‘์œ„ ๋ฌธ์ž์—ด ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” Marvin32 ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ 64๋น„ํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. MS ๊ณผ๋ชฉ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋ฝ‘์•˜์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด 64๋น„ํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜๋ฉฐ, ๋‹จ์ง€ ์ผ์„ ๋Š๋ฆฌ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋ฒ”์šฉ ํ•ด์‹œ ๊ฒฐํ•ฉ๊ธฐ๋Š” ์ด ์™„ํ™”๋ฅผ ๊ณ„์† ๋ฐœ์ „์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์ž‘์œ„ ์‹œ๋“œ์™€ ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅํ•œ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ๋ฌด์ž‘์œ„ ๋ฌธ์ž์—ด ํ•ด์‹ฑ๊ณผ ๋™์ผํ•œ Marvin32๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฌด์ž‘์œ„ ๋ฌธ์ž์—ด ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” Marvin32 ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ 64๋น„ํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. MS ๊ณผ๋ชฉ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋ฝ‘์•˜์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋“ค์ด 64๋น„ํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ถฉ๋ถ„ํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜๋ฉฐ, ๋‹จ์ง€ ์ผ์„ ๋Š๋ฆฌ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@jkotas , ์—ฐ๊ฒฐํ•œ ํ•ด์‹œ ์ฝ”๋“œ ๊ฒฐํ•ฉ๊ธฐ๋Š” Marvin32๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ non-randomized string.GetHashCode ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ์ˆœ์ง„ํ•œ DJBx33x ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฒ”์šฉ ํ•ด์‹œ ๊ฒฐํ•ฉ๊ธฐ๋Š” ์ด ์™„ํ™”๋ฅผ ๊ณ„์† ๋ฐœ์ „์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์ž‘์œ„ ์‹œ๋“œ์™€ ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅํ•œ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ๋ฌด์ž‘์œ„ ๋ฌธ์ž์—ด ํ•ด์‹ฑ๊ณผ ๋™์ผํ•œ Marvin32๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ์œ ํ˜•์€ ํ•ด์‹œ DoS ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•œ ์žฅ์†Œ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ถ”๊ฐ€/xor๋ฅผ ๋” ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋ฉฐ https://github.com/dotnet/coreclr/pull/4654 ์™€ ๊ฐ™์€ ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค

๋ฒ”์šฉ ํ•ด์‹œ ๊ฒฐํ•ฉ๊ธฐ๋Š” ์ด ์™„ํ™”๋ฅผ ๊ณ„์† ๋ฐœ์ „์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์ž‘์œ„ ์‹œ๋“œ์™€ ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅํ•œ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ๋ฌด์ž‘์œ„ ๋ฌธ์ž์—ด ํ•ด์‹ฑ๊ณผ ๋™์ผํ•œ Marvin32๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ C# ํŒ€๊ณผ ๋…ผ์˜ํ•˜์—ฌ ์™„ํ™”๋œ ValueTuple ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ฝ”๋“œ๋Š” ๊ณ ์œ„ํ—˜ ํ™˜๊ฒฝ์—์„œ๋„ ์‚ฌ์šฉ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  Tuple https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Tuple.cs#L60 ๋˜๋Š” System.Numerics.HashHelpers (๋ชจ๋“  ์žฅ์†Œ).

์ด์ œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•˜๊ธฐ ์ „์— API ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋”๋ผ๋„ ์™„์ „ํžˆ ๋ฌด์ž‘์œ„ํ™”๋œ ํ•ด์‹œ์ฝ”๋“œ ๊ฒฐํ•ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋น„์šฉ์„ ์ง€๋ถˆํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๋ฉด(๋ฌผ๋ก  ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ) ๋™์ผํ•œ ์ฃผ์ œ ์ „๋ฌธ๊ฐ€๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ์ œ์•ˆ๋œ API์— ๋”ฐ๋ผ ๋น„์šฉ์„ ์ง€๋ถˆํ•  ์˜ํ–ฅ์ด ์žˆ๋‹ค๋ฉด 512๋น„ํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์—ฌ์ „ํžˆ ๋™์ผํ•œ ๊ณต๊ฐœ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

์ด๊ฒƒ์€ ์ถ”๊ฐ€/xor๋ฅผ ๋” ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค์„ ๋Œ€์ƒ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋ฐ”๋กœ ๊ฒฌ๊ณ ํ•œ ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. .NET์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋Š” ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์— ์žˆ๋Š” ๋™์•ˆ IntPtr https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/IntPtr.cs#L119์— ๋Œ€ํ•ด ์žŠ์ง€ ๋งˆ์„ธ์š”.
bad ๊ฐ€ dab ์™€ ์ถฉ๋Œํ•˜๊ธฐ ๋•Œ๋ฌธ์— xor๋Š” ์•„๋งˆ๋„ ์ตœ์•…์˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์™„ํ™”๋œ ValueTuple ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„

์ข‹์€ ์ง€์ . ValueTupup์ด ๋ฐฐ์†ก๋˜์—ˆ๋Š”์ง€ ๋˜๋Š” ์•„์ง ์ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์‹œ๊ฐ„์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. https://github.com/dotnet/corefx/issues/14046์„ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค

IntPtr์„ ์žŠ์ง€ ๋ง์ž

์ด๊ฒƒ์€ ๊ณผ๊ฑฐ์˜ ์‹ค์ˆ˜์ž…๋‹ˆ๋‹ค ... ์ˆ˜์ •์˜ ๊ธฐ์ค€์€ ํ›จ์”ฌ ๋†’์Šต๋‹ˆ๋‹ค.

@jkotas

์ด๊ฒƒ์€ ๊ณผ๊ฑฐ์˜ ์‹ค์ˆ˜์ž…๋‹ˆ๋‹ค ... ์ˆ˜์ •์˜ ๊ธฐ์ค€์€ ํ›จ์”ฌ ๋†’์Šต๋‹ˆ๋‹ค.

.Net Core์˜ ์š”์  ์ค‘ ํ•˜๋‚˜๋Š” ๊ทธ๋Ÿฌํ•œ "์ž‘์€" ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ๊ธฐ์ค€์ด ํ›จ์”ฌ ๋‚ฎ์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ IntPtr.GetHashCode ๊ตฌํ˜„์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ(์‹ค์ œ๋กœ ํ•ด์„œ๋Š” ์•ˆ ๋จ) .Net Core ๋ฒ„์ „์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜์ง€ ์•Š๋„๋ก ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ "์ž‘์€" ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ๊ธฐ์ค€์€ ํ›จ์”ฌ ๋‚ฎ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ์ „์ฒด .NET Framework์™€ ๋น„๊ต๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ‘ธ์‹œํ•˜๋ ค๋ฉด ์—ฌ์ „ํžˆ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋ฉฐ ๊ณ ํ†ต๋ฐ›์„ ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ทผ์˜ ์˜ˆ๋Š” F#์„ ๊นจ๋œจ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ๋˜๋Œ๋ ค์ง„ Tuple<T> ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋ณ€๊ฒฝ์ž…๋‹ˆ๋‹ค. https://github.com/dotnet/coreclr/pull/6767#issuecomment -256896016

@jkotas

HashCode 64๋น„ํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด 32๋น„ํŠธ ํ™˜๊ฒฝ์—์„œ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋””์ž์ธ์ด perf๋ฅผ ์ฃฝ์ผ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ๋‹ค๋ฅธ ๋…์ž๋“ค์˜ ์˜๊ฒฌ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋” ํŒจํ„ด์ด ํ›จ์”ฌ ๋” ๋‚˜์œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์„ฑ๋Šฅ์„ ์ฃฝ์—ฌ๋ผ - ์•„๋‹ˆ. ๊ตฌ๋ฌธ ์„คํƒ•์— ๋Œ€ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜ - ์˜ˆ.

๊ตฌ๋ฌธ ์„คํƒ•์— ๋Œ€ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜ - ์˜ˆ.

ํ–ฅํ›„ JIT๋กœ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ธ๊ฐ€์š”?

์„ฑ๋Šฅ์„ ์ฃฝ์ž…๋‹ˆ๋‹ค - ์•„๋‹ˆ์š”.
๊ตฌ๋ฌธ ์„คํƒ•์— ๋Œ€ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜ - ์˜ˆ.

๊ทธ๊ฒƒ์€ ๊ตฌ๋ฌธ์ƒ์˜ ์„คํƒ• ์ด์ƒ์ž…๋‹ˆ๋‹ค. HashCode ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์˜ํ–ฅ์ด ์žˆ๋‹ค๋ฉด ๊ตฌ๋ฌธ์ƒ์˜ ์„คํƒ•์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฐ’ ์œ ํ˜•์€ ๋ฒ„๊ทธ ํŒœ์ž…๋‹ˆ๋‹ค.

์ด์ „์—์„œ ์ธ์šฉ:

์ด๊ฒƒ์ด ๋ฐ”๋กœ ๊ฒฌ๊ณ ํ•œ ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. .NET์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋Š” ์ž˜ ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฐ’ ์œ ํ˜•์ด ๋” ์ž˜ ๋ชจ๋ฅด๋Š” ๋Œ€๋‹ค์ˆ˜์˜ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ฐ•๋ ฅํ•œ API๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ฃผ์žฅํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ฐ’ ์œ ํ˜•์ด ๋” ์ž˜ ๋ชจ๋ฅด๋Š” ๋Œ€๋‹ค์ˆ˜์˜ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ฐ•๋ ฅํ•œ API๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ฃผ์žฅํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋™์˜ํ•˜๋‹ค. ์ƒ๊ฐํ•ด๋ณด๋ฉด, ๊ฐ€๋ณ€ ๊ตฌ์กฐ์ฒด ๋นŒ๋” ์œ ํ˜•์˜ ๊ฒฝ์šฐ๋ผ๋Š” ์‚ฌ์‹ค์ด ์•ˆํƒ€๊นŒ์šด ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ทธ๋“ค์—๊ฒŒ ๋ชจ๋“  ์‹œ๊ฐ„์„ ๋“ค์ด ๊ฝ‰ ์ข‹์€์ด๋‹ค์˜ ๋•Œ๋ฌธ์ด๋‹ค. [MustNotCopy] ์ฃผ์„์„

MustNotCopy๋Š” ๊ตฌ์กฐ์ฒด ์• ํ˜ธ๊ฐ€์˜ ๊ฟˆ์ด ์‹คํ˜„๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. @jaredpar?

MustNotCopy๋Š” ์Šคํƒ๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค ๐Ÿ˜„

ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ๋ง๊ณ  ํ•ด์‹œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

static class HashHelpers
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CombineHash(this int hash1, int hash2);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CombineHash<T>(this int hash, T value);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CombineHash<T>(this int hash, T value, IEqualityComparer<T> comparer);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CombineHash<T>(this int hash, IEnumerable<T> values);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int CombineHash<T>(this int hash, IEnumerable<T> values, IEqualityComparer<T> comparer);
}

๊ทธ๊ฒŒ ๋‹ค์•ผ! ๋น ๋ฅด๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

@AlexRadch ํ•ด์‹œ๋กœ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์ •์ˆ˜์— ๋Œ€ํ•œ ๋ฉ”์„œ๋“œ ๋ชฉ๋ก์„ ์˜ค์—ผ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ํ•ด์‹œ ์ฝ”๋“œ ๊ณ„์‚ฐ ์ฒด์ธ์„ ๊ณ„์†ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์ง€๋งŒ ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ•ฉ๋‹ˆ๊นŒ? 0์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์ฆ‰ 0.CombineHash(this.FirstName).CombineHash(this.LastName) .

์—…๋ฐ์ดํŠธ: dotnet/corefx#14046 ์˜ ์ฃผ์„ ์— ๋”ฐ๋ผ ๊ธฐ์กด ํ•ด์‹œ ์ˆ˜์‹์ด ValueTuple ๋Œ€ํ•ด ์œ ์ง€๋˜๊ธฐ๋กœ ๊ฒฐ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

@jamesqo ๋„์™€์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
@jkotas ๋ฐ @VSadov ์™€์˜ ๋งˆ์ง€๋ง‰ ํ† ๋ก ์—์„œ ์šฐ๋ฆฌ๋Š” ๋ฌด์ž‘์œ„ํ™”/์”จ๋”ฉ์„ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ ๋” ๋น„์‹ผ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์„ ๋ณด๋ฅ˜ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋ฌด์ž‘์œ„ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ํ–ฅํ›„ ํ•„์š”ํ•  ๊ฒฝ์šฐ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@jkotas , HashCode ๋Œ€ํ•œ ํ˜„์žฌ ROL 5 ๊ธฐ๋ฐ˜ ํ•ด์‹œ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๋‹ค์‹œ 4๋ฐ”์ดํŠธ๋กœ ์ถ•์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ๊ตฌ์กฐ์ฒด ๋ณต์‚ฌ์˜ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. HashCode.Empty ๊ฐ€ ์ž„์˜์˜ ํ•ด์‹œ ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@svic
์˜ˆ, ์ด๊ฒƒ์€ ๋ชจ๋“  ์ •์ˆ˜์— ๋Œ€ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค์—ผ์‹œํ‚ค์ง€๋งŒ ๋ถ„๋ฆฌ๋œ ์ด๋ฆ„ ๊ณต๊ฐ„์— ๋ฐฐ์น˜๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•ด์‹œ๋กœ ์ž‘์—…ํ•˜์ง€ ์•Š์œผ๋ฉด ํฌํ•จํ•˜์ง€ ์•Š๊ณ  ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

0.CombineHash(this.FirstName).CombineHash(this.LastName) ๋Š” this.FirstName.GetHash().CombineHash(this.LastName) ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‹œ๋“œ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ๋‹ค์Œ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

static class HashHelpers
{
    public static int ClassSeed<T>();
}

class SomeClass
{
    int GetHash()
    {
        return HashHelpers.ClassSeed<SomeClass>().CombineHash(value1).CombineHash(value2);
    }
}

๋”ฐ๋ผ์„œ ๊ฐ ํด๋ž˜์Šค์—๋Š” ํ•ด์‹œ๋ฅผ ๋ฌด์ž‘์œ„ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค๋ฅธ ์‹œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@jkotas , HashCode์— ๋Œ€ํ•œ ํ˜„์žฌ ROL 5 ๊ธฐ๋ฐ˜ ํ•ด์‹œ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๋‹ค์‹œ 4๋ฐ”์ดํŠธ๋กœ ์ถ•์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ณต๊ฐœ ํ”Œ๋žซํผ ํ•ด์‹œ์ฝ”๋“œ ๊ตฌ์ถ• ๋„์šฐ๋ฏธ๊ฐ€ 64๋น„ํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๊ฒฌ๊ณ ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 32๋น„ํŠธ ์ „์šฉ์ธ ๊ฒฝ์šฐ ํŠนํžˆ ๋” ๋งŽ์€ ์š”์†Œ, ๋ฐฐ์—ด ๋˜๋Š” ์ปฌ๋ ‰์…˜์„ ํ•ด์‹œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ๋•Œ ๋‚˜์œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ฒฝ์šฐ์™€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ๋ฌธ์„œ๋Š” ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ, ๋น„ํŠธ๋ฅผ ํ˜ผํ•ฉํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ถ”๊ฐ€ ์ง€์นจ์ด์ง€๋งŒ ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ๋ช…๋ น์€ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋„ˆ๋ฌด ์ ์€ ์–‘์˜ ๋ฏน์‹ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ๋งŽ์ด ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์‹ฌ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ ์€ ์–‘๋ณด๋‹ค ๋งŽ์€ ์–‘์˜ ๋ฏน์‹ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ œ์•ˆ๋œ API์˜ ํ˜•ํƒœ์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ์šฐ๋ คํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ํ•ด์‹œ ์ฝ”๋“œ ๊ฒฐํ•ฉ์ด ์•„๋‹ˆ๋ผ ํ•ด์‹œ ์ฝ”๋“œ ๊ตฌ์ถ•์œผ๋กœ ์ƒ๊ฐํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ”Œ๋žซํผ API๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ธฐ์ƒ์กฐ์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด์— ๋Œ€ํ•ด ๋” ๋‚˜์€ ํŒจํ„ด์ด ๋‚˜ํƒ€๋‚ ์ง€ ์ง€์ผœ๋ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด API๋กœ (์†Œ์Šค) nuget ํŒจํ‚ค์ง€๋ฅผ ๊ฒŒ์‹œํ•˜๊ฑฐ๋‚˜ corefx๊ฐ€ ์ด๋ฅผ ๋‚ด๋ถ€ ๋„์šฐ๋ฏธ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

64๋น„ํŠธ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ @jkotas ๋Š” ์ถœ๋ ฅ์ด ์ ์ ˆํ•œ ํ†ต๊ณ„์  ์†์„ฑ์„ ๊ฐ€์งˆ ๊ฒƒ์ด๋ผ๊ณ  ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒฐํ•ฉ ๊ธฐ๋Šฅ ์ž์ฒด๋Š” ๋‚ด๋ถ€ 64๋น„ํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฒฐํ•ฉ ๊ธฐ๋Šฅ์ด ์ข‹๋‹ค๋ฉด(ํ†ต๊ณ„์ ์œผ๋กœ) ๋œ ์„ž๋Š” ๊ฒƒ ์ด์ƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ํ•ด์‹ฑ์— ๋ฌด์ž‘์œ„ํ™”, ๋ˆˆ์‚ฌํƒœ ๋ฐ ๊ธฐํƒ€ ๊ด€์‹ฌ ์žˆ๋Š” ํ†ต๊ณ„์  ์†์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ์ˆ ์ ์œผ๋กœ ํŠน์ˆ˜ํ•˜๊ฒŒ ์กฐ์ž‘๋œ ํ•ด์‹œ ๊ธฐ๋Šฅ์„ ๋งํ•˜๋ฏ€๋กœ ํ˜ผํ•ฉ์ด ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

์ข‹์€ ํ•ด์‹œ ํ•จ์ˆ˜๊ฐ€ ๋ฌด์—‡์ธ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค(์ผ๋ถ€๋Š” xor ๊ฐ™์Šต๋‹ˆ๋‹ค. http://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and -์†๋„ ๋ฐ https://research.neustar.biz/2012/02/02/choosing-a-good-hash-function-part-3/

@jamesqo BTW, "์‹œ๋“œ๊ฐ€ ๋งค๋ฒˆ ๋ณ€๊ฒฝ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ํ•ด์‹œ(๋Ÿฐํƒ€์ž„ ํ•ด์‹œ๊ฐ€ ์•„๋‹˜)๋ฅผ ๊ฒฐํ•ฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค."์˜ ๊ฒฝ์šฐ ๊ฒฐํ•ฉ๊ธฐ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ... ์‹œ๋“œ๊ฐ€ ์žˆ๋Š” ๊ณต๊ฐœ ์ƒ์„ฑ์ž?

@jkotas

๊ณต๊ฐœ ํ”Œ๋žซํผ ํ•ด์‹œ์ฝ”๋“œ ๊ตฌ์ถ• ๋„์šฐ๋ฏธ๊ฐ€ 64๋น„ํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๊ฒฌ๊ณ ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 32๋น„ํŠธ ์ „์šฉ์ธ ๊ฒฝ์šฐ ํŠนํžˆ ๋” ๋งŽ์€ ์š”์†Œ, ๋ฐฐ์—ด ๋˜๋Š” ์ปฌ๋ ‰์…˜์„ ํ•ด์‹œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ๋•Œ ๋‚˜์œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๊ฒฐ๊ตญ ๋‹จ์ผ int ๋กœ ์••์ถ•๋˜๋Š” ์‹œ์ ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๊นŒ?

@jamesqo ์‹ค์ œ๋กœ๋Š” ์ƒํƒœ ํฌ๊ธฐ๊ฐ€ ๊ฒฌ๊ณ ์„ฑ์ด ์•„๋‹ˆ๋ผ ๊ธฐ๋Šฅ์—๋งŒ ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ๊ฒฐํ•ฉ์ด ๊ทธ๋Ÿฐ ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋„๋ก ์„ค๊ณ„๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋” ์•…ํ™”์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ•์ œ๋กœ ์ž„์˜์„ฑ์„ ์–ป์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๊ปํ•ด์•ผ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‚ญ๋น„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก : ํ•จ์ˆ˜๊ฐ€ ํ†ต๊ณ„์ ์œผ๋กœ ์šฐ์ˆ˜ํ•˜๊ฑฐ๋‚˜ ๋” ๋‚˜๋น ์งˆ ๊ฒƒ์ด ๊ฑฐ์˜ ๋ณด์žฅ๋œ๋‹ค๋Š” ์ ์„ ์ถ”๊ฐ€๋กœ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Š” ํ•ญ๋ชฉ ๊ฐ„์— ์ƒ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์ƒ๊ด€ ๊ด€๊ณ„๊ฐ€ ์—†์œผ๋ฉด 32๋น„ํŠธ ์ƒํƒœ์™€ ๋‹จ์ˆœ rotl(๋˜๋Š” xor)์ด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ƒ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฉด ์˜์กดํ•ฉ๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ฐœ๋ณ„ ๋ฌธ์ž์—์„œ ๋ฌธ์ž์—ด ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋ฐ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์‹ค์ œ๋กœ ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๊ฐ€๋Šฅ์„ฑ์€ ์—†์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

for (int i = 0; i < str.Length; i++)
   hashCodeBuilder.Add(str[i]);

์‹ค์ œ ๋ฌธ์ž์—ด์˜ ๋ฌธ์ž๋Š” ์ƒ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 32๋น„ํŠธ ์ƒํƒœ ๋ฐ ๋‹จ์ˆœ rotl ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด ์ข‹์ง€ ์•Š์€ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์‚ฌ์šฉ๋˜๋Š” ํ•ญ๋ชฉ์€ ์–ผ๋งˆ๋‚˜ ์ž์ฃผ ์ƒ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฉฐ ์–ผ๋งˆ๋‚˜ ๋‚˜์œ ๊ฒฐ๊ณผ๋ฅผ ์ค„๊นŒ์š”? ๋งํ•˜๊ธฐ๋Š” ์–ด๋ ต์ง€๋งŒ ์‹ค์ƒํ™œ์˜ ๊ฒƒ๋“ค์€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฐฉ์‹์œผ๋กœ ์ƒ๊ด€๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

API ์ง€์› Hash randomization์— ๋‹ค์Œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

namespace System
{
    public struct HashCode : IEquatable<HashCode>
    {
       // add this
       public static HashCode CreateRandomized(Type type);
       // or add this
       public static HashCode CreateRandomized<T>();
    }
}

@jkotas ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š์•˜ ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค . ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ๋ถ„๋ช…ํžˆ ๋งํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด ์†๋„๋ฅผ ๊ตํ™˜ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ตœ์†Œํ•œ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (์•„๋ฌด๋„ ์ด๊ฒƒ์œผ๋กœ ์–ด๋ฆฌ์„์€ ์ผ์„ ํ•  ์ˆ˜ ์—†์Œ). ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋น„-์•”ํ˜ธํ™” ํ•ด์‹ฑ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” ํ•ด์‹œ ์ฝ”๋“œ(์–ป๋Š” ๋งŒํผ ๋ฌด์ž‘์œ„์ž„)๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด๋ผ๋Š” ๋””์ž์ธ์„ ํ•œ ๋ฒˆ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ฆฌ์„์€ ์ผ์„ ์•„๋ฌด๋„ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋ผ๋ฉด 64๋น„ํŠธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„๋ฌด ๊ฒƒ๋„ ๊ณ ์น  ์ˆ˜ ์—†๊ณ  ๋‹จ์ง€ ๋ฌธ์ œ๋ฅผ ์ˆจ๊ธฐ๊ณ  ์žˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ƒ๊ด€๊ด€๊ณ„๋ฅผ ์ด์šฉํ•˜๋Š” ์ž…๋ ฅ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ 18์ผ ์ „์— ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ์ฃผ์žฅ์œผ๋กœ ์šฐ๋ฆฌ๋ฅผ ๋‹ค์‹œ๊ธˆ ์ง€์ ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐ: https://github.com/dotnet/corefx/issues/8034#issuecomment -261301533

๋‚˜๋Š” ์ด๊ฒƒ์ด ๋น„-์•”ํ˜ธํ™” ํ•ด์‹ฑ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒ๊ด€๋˜์ง€ ์•Š์€ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด๋ผ๋Š” ๋””์ž์ธ์„ ํ•œ ๋ฒˆ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์ƒ๊ด€๋˜์ง€ ์•Š์€ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์€ xor...

์‚ฌ์‹ค์ด์ง€๋งŒ ์ง€๋‚œ ๋ฒˆ์—๋Š” ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(IntPtr์ด ์ƒ๊ฐ๋‚ฉ๋‹ˆ๋‹ค). Rotation ๋ฐ XOR(ํ˜„์žฌ)๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋น ๋ฅด๋ฉฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ผ์ข…์˜ ๊ด€๋ จ ํ•ญ๋ชฉ์„ ๋„ฃ์–ด๋„ ์†์‹ค์ด ์—†์Šต๋‹ˆ๋‹ค.

public static HashCode CreateRandomized(Type type); ๋˜๋Š” public static HashCode CreateRandomized<T>(); ๋ฐฉ๋ฒ• ๋˜๋Š” ๋‘˜ ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด์‹œ ์ฝ”๋“œ ๋ฌด์ž‘์œ„ํ™”๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

@jkotas ๋” ๋‚˜์€ ํŒจํ„ด์„ ์ฐพ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. C# 7 ref ๋ฐ˜ํ™˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๋งค๋ฒˆ HashCode ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  ๋ ˆ์ง€์Šคํ„ฐ์— ๋งž๋Š” ref HashCode ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

public struct HashCode
{
    private readonly long _value;

    public ref HashCode Combine(int hashCode)
    {
        CombineCore(ref _value, hashCode); // note: modifies the struct in-place
        return ref this;
    }
}

์‚ฌ์šฉ๋ฒ•์€ ์ด์ „๊ณผ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

return HashCode.Combine(1)
    .Combine(2).Combine(3);

์œ ์ผํ•œ ๋‹จ์ ์€ ๋‹ค์‹œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ์ฒด๋กœ ๋Œ์•„๊ฐ„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณต์‚ฌ์™€ ๋ถˆ๋ณ€์„ฑ์„ ๋™์‹œ์— ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

( ref this ๋Š” ์•„์ง ์ž‘๋™ํ•˜์ง€ ์•Š์ง€๋งŒ ์—ฌ๊ธฐ ์—์„œ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด Roslyn์—์„œ PR์„ ๋ด…๋‹ˆ๋‹ค


@AlexRadch ์œ ํ˜•์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์–ป๋Š” ๋ฐ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ํ•ด์‹œ๋ฅผ ์œ ํ˜•๊ณผ ๋” ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด ํ˜„๋ช…ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@jamesqo public static HashCode CreateRandomized<T>(); ์œ ํ˜• ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์œ ํ˜•์— ๋Œ€ํ•ด ์ž„์˜์˜ HashCode๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

@jamesqo " ref this ์ด(๊ฐ€) ์•„์ง ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค". ๋กœ์Šฌ๋ฆฐ์˜ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋˜๋”๋ผ๋„ ์ผ๋‹จ ref this ์ž ์‹œ ๋™์•ˆ corefx์˜ REPO (๋‚˜๋Š” ํ™•์‹คํžˆ ์–ผ๋งˆ๋‚˜ ์˜ค๋ž˜, @stephentoub ์•„๋งˆ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์•„์š”)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋””์ž์ธ ๋…ผ์˜๋Š” ์—ฌ๊ธฐ์— ์ˆ˜๋ ด๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ 200๊ฐœ์˜ ๋Œ“๊ธ€์€ ๋”ฐ๋ผ๊ฐ€๊ธฐ ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ๋‹ค์Œ ์ฃผ์— @jkotas ๋ฅผ ์žก๊ณ  ๋‹ค์Œ ํ™”์š”์ผ์— API ๊ฒ€ํ† ์—์„œ ์ œ์•ˆ์„ ํ”Œ๋Ÿฌ์‹œํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ถ”๊ฐ€ ์˜๊ฒฌ์„ ์œ„ํ•ด ์ œ์•ˆ์„œ๋ฅผ ์—ฌ๊ธฐ์— ๋‹ค์‹œ ๊ฒŒ์‹œํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜†์—์„œ: ๋‚˜๋Š” ๊ธด ํ† ๋ก ์„ ๋”ฐ๋ฅด๋Š” ๋ถ€๋‹ด์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ์ฃผ์— ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ๊ฐ€์งˆ ๋•Œ ์ด ๋ฌธ์ œ๋ฅผ ๋‹ซ๊ณ  "์ถ•๋ณต๋ฐ›์€ ์ œ์•ˆ"์œผ๋กœ ์ƒˆ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์œ ์ƒ๊ฐ์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

@jcouv ์•„์ง ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ์ด ๋””์ž์ธ์ด ์ถœ์‹œ๋  ๋•Œ ๋”ฐ๋ผ๊ฐˆ Unsafe ์‚ฌ์šฉํ•˜์—ฌ ์ผ์‹œ์ ์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.)

@karelz OK :smile: ๋‚˜์ค‘์— ์‹œ๊ฐ„์ด ๋˜๋ฉด ์ด ์ œ์•ˆ์„ ๋‹ซ๊ณ  ์ƒˆ ์ œ์•ˆ์„ ์—ด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋™์˜ํ•œ๋‹ค; ๋‚ด ๋ธŒ๋ผ์šฐ์ €๋Š” 200๊ฐœ ์ด์ƒ์˜ ๋Œ“๊ธ€์„ ์ž˜ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@karelz ๋‚˜๋Š” ๊ฑธ๋ฆผ๋Œ์„ ์ณค๋‹ค; ๋ฌธ์ œ์˜ PR์ด ๊ฐ’ ์œ ํ˜•์ด ์•„๋‹Œ ์ฐธ์กฐ ์œ ํ˜•์— ๋Œ€ํ•ด ref this ๋ฐ˜ํ™˜์„ ํ™œ์„ฑํ™”ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•œ ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ref this ๋Š” ๊ตฌ์กฐ์ฒด์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐ˜ํ™˜๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด์œ ๋Š” ์—ฌ๊ธฐ ๋ฅผ ์ฐธ์กฐ

์–ด์จŒ๋“  ์ด ๋ฌธ์ œ๋Š” ๋‹ซ๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค. https://github.com/dotnet/corefx/issues/14354

C#vNext๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ง€๋งŒ ๊ฐ’ ์œ ํ˜• ํ™•์žฅ ๋ฉ”์„œ๋“œ ๊ฒŒ์‹œ๋ฌผ https://github.com/dotnet/roslyn/pull/15650 ์—์„œ ref "this"๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@benaadams

C#vNext๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ง€๋งŒ dotnet/roslyn#15650 ์ดํ›„์˜ ๊ฐ’ ์œ ํ˜• ํ™•์žฅ ๋ฉ”์„œ๋“œ์—์„œ ref "this"๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ณ์€. ref this ํ™•์žฅ ๋ฉ”์„œ๋“œ์—์„œ this ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜ ๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์—์„œ this ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ์ง€์— ๋Œ€ํ•œ ํ”ผํˆฌ์„ฑ์ด์˜ ํ‰์ƒ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค :(

@redknightlois

์šฐ๋ฆฌ๊ฐ€ ์—„๊ฒฉํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์œ ์ผํ•œ ํ•ด์‹œ๋Š” uint ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•ด๋‹น ์กฐ๋ช… ์•„๋ž˜์—์„œ int ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๊ณผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CLS ์ค€์ˆ˜? ๋ถ€ํ˜ธ ์—†๋Š” ์ •์ˆ˜๋Š” CLS ๊ทœ๊ฒฉ์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰