Skip to content

Commit

Permalink
Merge pull request #39 from diegofrata/deep-equality
Browse files Browse the repository at this point in the history
Fix comparison to support deep equality on non-sealed types.
  • Loading branch information
diegofrata authored Dec 31, 2022
2 parents cf185f8 + 4a96773 commit 4047e06
Show file tree
Hide file tree
Showing 84 changed files with 912 additions and 174 deletions.
30 changes: 30 additions & 0 deletions Generator.Equals.Runtime/DefaultEqualityComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.Generic;

namespace Generator.Equals
{
public class DefaultEqualityComparer<T> : IEqualityComparer<T>
{
public static DefaultEqualityComparer<T> Default { get; }= new DefaultEqualityComparer<T>();

private static readonly IEqualityComparer<T> _underlying;

static DefaultEqualityComparer()
{
if (typeof(T).IsSealed)
_underlying = EqualityComparer<T>.Default;
else
_underlying = new ObjectEqualityComparer();
}

public bool Equals(T x, T y) => _underlying.Equals(x, y);

public int GetHashCode(T obj) => _underlying.GetHashCode(obj);

private class ObjectEqualityComparer : IEqualityComparer<T>
{
public bool Equals(T x, T y) => object.Equals(x, y);

public int GetHashCode(T obj) => obj!.GetHashCode();
}
}
}
2 changes: 1 addition & 1 deletion Generator.Equals.Runtime/DictionaryEqualityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public int GetHashCode(KeyValuePair<TKey, TValue> obj)

public IEqualityComparer<TValue> ValueEqualityComparer { get; }

public DictionaryEqualityComparer() : this(EqualityComparer<TValue>.Default)
public DictionaryEqualityComparer() : this(DefaultEqualityComparer<TValue>.Default)
{
}

Expand Down
2 changes: 1 addition & 1 deletion Generator.Equals.Runtime/OrderedEqualityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class OrderedEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>

public IEqualityComparer<T> EqualityComparer { get; }

public OrderedEqualityComparer() : this(EqualityComparer<T>.Default)
public OrderedEqualityComparer() : this(DefaultEqualityComparer<T>.Default)
{
}

Expand Down
2 changes: 1 addition & 1 deletion Generator.Equals.Runtime/SetEqualityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class SetEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>

public IEqualityComparer<T> EqualityComparer { get; }

public SetEqualityComparer() : this(EqualityComparer<T>.Default)
public SetEqualityComparer() : this(DefaultEqualityComparer<T>.Default)
{
}

Expand Down
2 changes: 1 addition & 1 deletion Generator.Equals.Runtime/UnorderedEqualityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class UnorderedEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>

public IEqualityComparer<T> EqualityComparer { get; }

public UnorderedEqualityComparer() : this(EqualityComparer<T>.Default)
public UnorderedEqualityComparer() : this(DefaultEqualityComparer<T>.Default)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ partial class Sample : global::System.IEquatable<Sample>
public static bool operator ==(
global::Generator.Equals.Tests.Classes.CustomEquality.Sample? left,
global::Generator.Equals.Tests.Classes.CustomEquality.Sample? right) =>
global::System.Collections.Generic.EqualityComparer<global::Generator.Equals.Tests.Classes.CustomEquality.Sample?>.Default
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.CustomEquality.Sample?>.Default
.Equals(left, right);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//HintName: Generator.Equals.Tests.Classes.DeepEquality.Manager.Generator.Equals.g.cs

#nullable enable
#pragma warning disable CS0612,CS0618

namespace Generator.Equals.Tests.Classes
{
partial class DeepEquality
{
partial class Manager : global::System.IEquatable<Manager>
{
/// <summary>
/// Indicates whether the object on the left is equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator ==(
global::Generator.Equals.Tests.Classes.DeepEquality.Manager? left,
global::Generator.Equals.Tests.Classes.DeepEquality.Manager? right) =>
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Manager?>.Default
.Equals(left, right);

/// <summary>
/// Indicates whether the object on the left is not equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are not equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator !=(global::Generator.Equals.Tests.Classes.DeepEquality.Manager? left, global::Generator.Equals.Tests.Classes.DeepEquality.Manager? right) =>
!(left == right);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override bool Equals(object? obj) =>
Equals(obj as global::Generator.Equals.Tests.Classes.DeepEquality.Manager);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public bool Equals(global::Generator.Equals.Tests.Classes.DeepEquality.Manager? other)
{
return
base.Equals(other as global::Generator.Equals.Tests.Classes.DeepEquality.Person)
&& global::Generator.Equals.DefaultEqualityComparer<global::System.String>.Default.Equals(this.Department!, other.Department!)
;
}

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override int GetHashCode()
{
var hashCode = new global::System.HashCode();

hashCode.Add(base.GetHashCode());
hashCode.Add(
this.Department!,
global::Generator.Equals.DefaultEqualityComparer<global::System.String>.Default);

return hashCode.ToHashCode();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//HintName: Generator.Equals.Tests.Classes.DeepEquality.Person.Generator.Equals.g.cs

#nullable enable
#pragma warning disable CS0612,CS0618

namespace Generator.Equals.Tests.Classes
{
partial class DeepEquality
{
partial class Person : global::System.IEquatable<Person>
{
/// <summary>
/// Indicates whether the object on the left is equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator ==(
global::Generator.Equals.Tests.Classes.DeepEquality.Person? left,
global::Generator.Equals.Tests.Classes.DeepEquality.Person? right) =>
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Person?>.Default
.Equals(left, right);

/// <summary>
/// Indicates whether the object on the left is not equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are not equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator !=(global::Generator.Equals.Tests.Classes.DeepEquality.Person? left, global::Generator.Equals.Tests.Classes.DeepEquality.Person? right) =>
!(left == right);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override bool Equals(object? obj) =>
Equals(obj as global::Generator.Equals.Tests.Classes.DeepEquality.Person);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public bool Equals(global::Generator.Equals.Tests.Classes.DeepEquality.Person? other)
{
return
!ReferenceEquals(other, null) && this.GetType() == other.GetType()
&& global::Generator.Equals.DefaultEqualityComparer<global::System.Int32>.Default.Equals(this.Age!, other.Age!)
;
}

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override int GetHashCode()
{
var hashCode = new global::System.HashCode();

hashCode.Add(this.GetType());
hashCode.Add(
this.Age!,
global::Generator.Equals.DefaultEqualityComparer<global::System.Int32>.Default);

return hashCode.ToHashCode();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//HintName: Generator.Equals.Tests.Classes.DeepEquality.Sample.Generator.Equals.g.cs

#nullable enable
#pragma warning disable CS0612,CS0618

namespace Generator.Equals.Tests.Classes
{
partial class DeepEquality
{
partial class Sample : global::System.IEquatable<Sample>
{
/// <summary>
/// Indicates whether the object on the left is equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator ==(
global::Generator.Equals.Tests.Classes.DeepEquality.Sample? left,
global::Generator.Equals.Tests.Classes.DeepEquality.Sample? right) =>
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Sample?>.Default
.Equals(left, right);

/// <summary>
/// Indicates whether the object on the left is not equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are not equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator !=(global::Generator.Equals.Tests.Classes.DeepEquality.Sample? left, global::Generator.Equals.Tests.Classes.DeepEquality.Sample? right) =>
!(left == right);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override bool Equals(object? obj) =>
Equals(obj as global::Generator.Equals.Tests.Classes.DeepEquality.Sample);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public bool Equals(global::Generator.Equals.Tests.Classes.DeepEquality.Sample? other)
{
return
!ReferenceEquals(other, null) && this.GetType() == other.GetType()
&& global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Person>.Default.Equals(this.Person!, other.Person!)
;
}

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override int GetHashCode()
{
var hashCode = new global::System.HashCode();

hashCode.Add(this.GetType());
hashCode.Add(
this.Person!,
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Person>.Default);

return hashCode.ToHashCode();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//HintName: Generator.Equals.Tests.Classes.DeepEquality.Manager.Generator.Equals.g.cs

#nullable enable
#pragma warning disable CS0612,CS0618

namespace Generator.Equals.Tests.Classes
{
partial class DeepEquality
{
partial class Manager : global::System.IEquatable<Manager>
{
/// <summary>
/// Indicates whether the object on the left is equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator ==(
global::Generator.Equals.Tests.Classes.DeepEquality.Manager? left,
global::Generator.Equals.Tests.Classes.DeepEquality.Manager? right) =>
global::Generator.Equals.DefaultEqualityComparer<global::Generator.Equals.Tests.Classes.DeepEquality.Manager?>.Default
.Equals(left, right);

/// <summary>
/// Indicates whether the object on the left is not equal to the object on the right.
/// </summary>
/// <param name="left">The left object</param>
/// <param name="right">The right object</param>
/// <returns>true if the objects are not equal; otherwise, false.</returns>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public static bool operator !=(global::Generator.Equals.Tests.Classes.DeepEquality.Manager? left, global::Generator.Equals.Tests.Classes.DeepEquality.Manager? right) =>
!(left == right);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override bool Equals(object? obj) =>
Equals(obj as global::Generator.Equals.Tests.Classes.DeepEquality.Manager);

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public bool Equals(global::Generator.Equals.Tests.Classes.DeepEquality.Manager? other)
{
return
base.Equals(other as global::Generator.Equals.Tests.Classes.DeepEquality.Person)
&& global::Generator.Equals.DefaultEqualityComparer<global::System.String>.Default.Equals(this.Department!, other.Department!)
;
}

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
public override int GetHashCode()
{
var hashCode = new global::System.HashCode();

hashCode.Add(base.GetHashCode());
hashCode.Add(
this.Department!,
global::Generator.Equals.DefaultEqualityComparer<global::System.String>.Default);

return hashCode.ToHashCode();
}
}
}
}
Loading

0 comments on commit 4047e06

Please sign in to comment.