Skip to content

Commit 71b9e44

Browse files
authored
Implement GetHashCode() via HashCode.Combine() (#268)
1 parent 19d842c commit 71b9e44

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+127
-416
lines changed

Extensions/Xtensive.Orm.Security/Permission.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,7 @@ public override bool Equals(object obj)
5656
}
5757

5858
/// <inheritdoc/>
59-
public override int GetHashCode()
60-
{
61-
unchecked {
62-
int result = (Type != null ? Type.GetHashCode() : 0);
63-
result = (result*397) ^ CanRead.GetHashCode();
64-
result = (result*397) ^ CanWrite.GetHashCode();
65-
result = (result*397) ^ (Query != null ? Query.GetHashCode() : 0);
66-
return result;
67-
}
68-
}
59+
public override int GetHashCode() => HashCode.Combine(Type, CanRead, CanWrite, Query);
6960

7061
#endregion
7162

Orm/Xtensive.Orm.Tests.Core/Caching/CachePerformanceTest.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,7 @@ public override bool Equals(object obj)
5252
return Equals(obj as Item);
5353
}
5454

55-
public override int GetHashCode()
56-
{
57-
return (Value!=null ? Value.GetHashCode() : 0);
58-
}
55+
public override int GetHashCode() => Value?.GetHashCode() ?? 0;
5956

6057
public override string ToString()
6158
{
@@ -174,4 +171,4 @@ private void FetchTest(int count)
174171
}
175172
}
176173
}
177-
}
174+
}

Orm/Xtensive.Orm.Tests.Core/Caching/WeakestCacheTest.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@ public override bool Equals(object obj)
3636
return Equals(obj as Item);
3737
}
3838

39-
public override int GetHashCode()
40-
{
41-
return (Value != null ? Value.GetHashCode() : 0);
42-
}
39+
public override int GetHashCode() => Value?.GetHashCode() ?? 0;
4340

4441
public override string ToString()
4542
{
@@ -197,4 +194,4 @@ public void ProfileTest()
197194
}
198195
}
199196
}
200-
}
197+
}

Orm/Xtensive.Orm.Tests.Core/Modelling/IndexingModel/TypeInfo.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,7 @@ public override bool Equals(object obj)
100100
}
101101

102102
/// <inheritdoc/>
103-
public override int GetHashCode()
104-
{
105-
unchecked {
106-
int result = (Type!=null ? Type.GetHashCode() : 0);
107-
result = (result * 397) ^ (IsNullable ? 1 : 0);
108-
result = (result * 397) ^ Length;
109-
result = (result * 397) ^ Scale;
110-
result = (result * 397) ^ Precision;
111-
if (Culture!=null)
112-
result = (result * 397) ^ Culture.GetHashCode();
113-
return result;
114-
}
115-
}
103+
public override int GetHashCode() => HashCode.Combine(Type, IsNullable, Length, Scale, Precision, Culture);
116104

117105
/// <summary>
118106
/// Implements the operator ==.

Orm/Xtensive.Orm.Tests.Framework/Dynamic.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,13 @@ internal class Signature : IEquatable<Signature>
219219
public Signature(IEnumerable<DynamicProperty> properties)
220220
{
221221
this.properties = properties.ToArray();
222-
hashCode = 0;
222+
HashCode hc = new();
223223
foreach (DynamicProperty p in properties)
224224
{
225-
hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
225+
hc.Add(p.Name);
226+
hc.Add(p.Type);
226227
}
228+
hashCode = hc.ToHashCode();
227229
}
228230

229231
#region IEquatable<Signature> Members
@@ -241,10 +243,7 @@ public bool Equals(Signature other)
241243

242244
#endregion
243245

244-
public override int GetHashCode()
245-
{
246-
return hashCode;
247-
}
246+
public override int GetHashCode() => hashCode;
248247

249248
public override bool Equals(object obj)
250249
{
@@ -2298,4 +2297,4 @@ internal static class Res
22982297
public const string CloseBracketOrCommaExpected = "']' or ',' expected";
22992298
public const string IdentifierExpected = "Identifier expected";
23002299
}
2301-
}
2300+
}

Orm/Xtensive.Orm.Tests/Linq/LocalCollectionsTest.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,7 @@ public override bool Equals(object obj)
5454
return Equals((Poco<T>) obj);
5555
}
5656

57-
public override int GetHashCode()
58-
{
59-
return Value.GetHashCode();
60-
}
57+
public override int GetHashCode() => Value.GetHashCode();
6158
}
6259

6360
public class Poco<T1, T2>
@@ -85,12 +82,7 @@ public override bool Equals(object obj)
8582
return Equals((Poco<T1, T2>) obj);
8683
}
8784

88-
public override int GetHashCode()
89-
{
90-
unchecked {
91-
return (Value1.GetHashCode() * 397) ^ Value2.GetHashCode();
92-
}
93-
}
85+
public override int GetHashCode() => HashCode.Combine(Value1, Value2);
9486

9587
public Poco(T1 Value1, T2 Value2)
9688
{
@@ -137,15 +129,7 @@ public override bool Equals(object obj)
137129
return Equals((Poco<T1, T2, T3>) obj);
138130
}
139131

140-
public override int GetHashCode()
141-
{
142-
unchecked {
143-
int result = Value1.GetHashCode();
144-
result = (result * 397) ^ Value2.GetHashCode();
145-
result = (result * 397) ^ Value3.GetHashCode();
146-
return result;
147-
}
148-
}
132+
public override int GetHashCode() => HashCode.Combine(Value1, Value2, Value3);
149133

150134
public Poco()
151135
{
@@ -942,4 +926,4 @@ private IEnumerable<Poco<int, decimal, string>> GetLocalItems(int count)
942926
.ToList();
943927
}
944928
}
945-
}
929+
}

Orm/Xtensive.Orm/Annotations.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,7 @@ public override bool Equals(object obj)
7575
/// Returns the hash code for this instance.
7676
/// </summary>
7777
/// <returns>A hash code for the current <see cref="LocalizationRequiredAttribute"/>.</returns>
78-
public override int GetHashCode()
79-
{
80-
return base.GetHashCode();
81-
}
78+
public override int GetHashCode() => base.GetHashCode();
8279
}
8380

8481
/// <summary>
@@ -521,4 +518,4 @@ public PathReferenceAttribute([PathReference] string basePath)
521518

522519
[UsedImplicitly] public string BasePath { get; private set; }
523520
}
524-
}
521+
}

Orm/Xtensive.Orm/Arithmetic/ArithmeticRules.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,7 @@ public override bool Equals(object obj) =>
4545
obj is ArithmeticRules other && Equals(other);
4646

4747
/// <inheritdoc/>
48-
public override int GetHashCode()
49-
{
50-
return ((byte)overflowBehavior << 8) | (byte)nullBehavior;
51-
}
48+
public override int GetHashCode() => ((byte) overflowBehavior << 8) | (byte) nullBehavior;
5249

5350

5451
// Constructors

Orm/Xtensive.Orm/Caching/WeakestCache.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ public override bool Equals(object obj)
101101
return Equals((WeakEntry) obj);
102102
}
103103

104-
public override int GetHashCode()
105-
{
106-
return hashCode;
107-
}
104+
public override int GetHashCode() => hashCode;
108105

109106
#endregion
110107

Orm/Xtensive.Orm/Collections/FlagCollection.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,12 +333,7 @@ public override bool Equals(object obj)
333333
}
334334

335335
/// <inheritdoc/>
336-
public override int GetHashCode()
337-
{
338-
int result = keys.GetHashCode();
339-
result = 29*result + flags.GetHashCode();
340-
return result;
341-
}
336+
public override int GetHashCode() => HashCode.Combine(keys, flags);
342337

343338
#endregion
344339

@@ -407,4 +402,4 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte
407402

408403
#endregion
409404
}
410-
}
405+
}

Orm/Xtensive.Orm/Collections/TypeRegistration.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,7 @@ public override bool Equals(object obj)
6969
}
7070

7171
/// <inheritdoc/>
72-
public override int GetHashCode()
73-
{
74-
unchecked {
75-
int result = (type!=null ? type.GetHashCode() : 0);
76-
result = (result * 397) ^ (assembly!=null ? assembly.GetHashCode() : 0);
77-
result = (result * 397) ^ (@namespace!=null ? @namespace.GetHashCode() : 0);
78-
return result;
79-
}
80-
}
72+
public override int GetHashCode() => HashCode.Combine(type, assembly, @namespace);
8173

8274
/// <inheritdoc/>
8375
public static bool operator ==(TypeRegistration left, TypeRegistration right)
@@ -128,4 +120,4 @@ public TypeRegistration(Assembly assembly, string @namespace)
128120
this.@namespace = @namespace;
129121
}
130122
}
131-
}
123+
}

Orm/Xtensive.Orm/Comparison/ComparisonRule.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,7 @@ public override bool Equals(object obj) =>
8383
obj is ComparisonRule other && Equals(other);
8484

8585
/// <inheritdoc/>
86-
public override int GetHashCode()
87-
{
88-
int result = (int)Direction;
89-
if (Culture != null)
90-
result ^= Culture.GetHashCode();
91-
return result;
92-
}
86+
public override int GetHashCode() => HashCode.Combine(Direction, Culture);
9387

9488
#endregion
9589

@@ -200,4 +194,4 @@ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext contex
200194
info.AddValue(nameof(Culture), cultureId);
201195
}
202196
}
203-
}
197+
}

Orm/Xtensive.Orm/Comparison/ComparisonRules.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public sealed class ComparisonRules :
2323
{
2424
private readonly ComparisonRule value;
2525
private readonly ComparisonRules[] composite;
26-
private volatile int cachedHashCode;
26+
private long cachedHashCode;
2727

2828
/// <summary>
2929
/// Predefined rules with <see cref="Direction"/> = <see cref="Direction.None"/>.
@@ -199,18 +199,20 @@ public override bool Equals(object obj) =>
199199
/// <inheritdoc/>
200200
public override int GetHashCode()
201201
{
202-
if (cachedHashCode==0) lock (composite) if (cachedHashCode==0) {
202+
var h = Volatile.Read(ref cachedHashCode);
203+
if (h == 0) {
203204
int tailIndex = TailIndex;
204-
int result = value.GetHashCode();
205-
if (tailIndex==0 && IsRecursive)
206-
result ^= 29 * 22; // Hash affection by IsRecursive
205+
HashCode hc = new();
206+
hc.Add(value);
207+
if (tailIndex == 0 && IsRecursive)
208+
hc.Add(1); // Hash affection by IsRecursive
207209
else
208-
result ^= 29 * composite[tailIndex].GetHashCode();
210+
hc.Add(composite[tailIndex]);
209211
for (int i = 0; i < tailIndex; i++)
210-
result ^= (composite[i].GetHashCode() << i);
211-
cachedHashCode = result;
212+
hc.Add(composite[i]);
213+
Volatile.Write(ref cachedHashCode, (long)hc.ToHashCode() | (1L << 63)); // Set the highest bit as HasValue flag even when `hashCode == 0`
212214
}
213-
return cachedHashCode;
215+
return (int) h;
214216
}
215217

216218
#endregion
@@ -313,4 +315,4 @@ private ComparisonRules(ComparisonRule value, ComparisonRules[] composite, bool
313315
this.composite = composite;
314316
}
315317
}
316-
}
318+
}

Orm/Xtensive.Orm/Comparison/Internals/NoSystemComparerHandler.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,11 @@ public bool Equals(T other)
3636
}
3737

3838
/// <exception cref="NotSupportedException"><c>NotSupportedException</c>.</exception>
39-
public override int GetHashCode()
40-
{
39+
public override int GetHashCode() =>
4140
throw new NotSupportedException(string.Format(
4241
Strings.ExTypeXMustImplementY,
4342
typeof(T).GetShortName(),
4443
typeof(IEquatable<T>).GetShortName()));
45-
}
4644

4745

4846
// Constructors
@@ -51,4 +49,4 @@ private NoSystemComparerHandler()
5149
{
5250
}
5351
}
54-
}
52+
}

Orm/Xtensive.Orm/Conversion/Biconverter.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,7 @@ public override bool Equals(object obj) =>
5757
obj is Biconverter<TFrom, TTo> other && Equals(other);
5858

5959
/// <inheritdoc/>
60-
public override int GetHashCode()
61-
{
62-
unchecked {
63-
return ((ConvertForward!=null ? ConvertForward.GetHashCode() : 0) * 397) ^ (ConvertBackward!=null ? ConvertBackward.GetHashCode() : 0);
64-
}
65-
}
60+
public override int GetHashCode() => HashCode.Combine(ConvertForward, ConvertBackward);
6661

6762
#endregion
6863

Orm/Xtensive.Orm/Core/HasVersion{TValue,TVersion}.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,7 @@ public override bool Equals(object obj) =>
6161
obj is HasVersion<TValue, TVersion> other && Equals(other);
6262

6363
/// <inheritdoc/>
64-
public override int GetHashCode()
65-
{
66-
unchecked {
67-
return
68-
((Value!=null ? Value.GetHashCode() : 0) * 397) ^
69-
(Version!=null ? Version.GetHashCode() : 0);
70-
}
71-
}
64+
public override int GetHashCode() => HashCode.Combine(Value, Version);
7265

7366
/// <summary>
7467
/// Checks specified objects for equality.
@@ -114,4 +107,4 @@ public HasVersion(TValue value, TVersion version)
114107
Version = version;
115108
}
116109
}
117-
}
110+
}

Orm/Xtensive.Orm/Core/Pair{TFirst,TSecond}.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,7 @@ public override bool Equals(object obj) =>
5757
obj is Pair<TFirst, TSecond> other && Equals(other);
5858

5959
/// <inheritdoc/>
60-
public override int GetHashCode()
61-
{
62-
unchecked {
63-
return ((First?.GetHashCode() ?? 0) * 397) ^ (Second?.GetHashCode() ?? 0);
64-
}
65-
}
60+
public override int GetHashCode() => HashCode.Combine(First, Second);
6661

6762
/// <summary>
6863
/// Checks specified objects for equality.

0 commit comments

Comments
 (0)