Generate Equals, GetHashCode and operator methods from properties for classes decorated with an [Equals] Attribute
See Milestones for release notes.
This is an add-in for Fody
It is expected that all developers using Fody either become a Patron on OpenCollective, or have a Tidelift Subscription. See Licensing/Patron FAQ for more information.
See also Fody usage.
Install the Equals.Fody NuGet package and update the Fody NuGet package:
PM> Install-Package Fody
PM> Install-Package Equals.FodyThe Install-Package Fody is required since NuGet always defaults to the oldest, and most buggy, version of any dependency.
Add <Equals/> to FodyWeavers.xml
<Weavers>
<Equals/>
</Weavers>[Equals]
public class Point
{
public int X { get; set; }
public int Y { get; set; }
[IgnoreDuringEquals]
public int Z { get; set; }
[CustomEqualsInternal]
bool CustomLogic(Point other)
{
return Z == other.Z || Z == 0 || other.Z == 0;
}
public static bool operator ==(Point left, Point right) => Operator.Weave(left, right);
public static bool operator !=(Point left, Point right) => Operator.Weave(left, right);
}
[Equals]
public class CustomGetHashCode
{
public int X { get; set; }
[IgnoreDuringEquals]
public int Z { get; set; }
[CustomGetHashCode]
int CustomGetHashCodeMethod()
{
return 42;
}
public static bool operator ==(CustomGetHashCode left, CustomGetHashCode right) => Operator.Weave(left, right);
public static bool operator !=(CustomGetHashCode left, CustomGetHashCode right) => Operator.Weave(left, right);
}Note:
- unless you specify
[Equals(DoNotAddEqualityOperators = true)], you must always add the==and!=method stubs with theOperator.Weave()implementation (if you want to know why, see #10). - adding the
==and!=operators will result in compiler warnings CS0660 and CS0661, which tell you to implement customEqualsandGetHashCodeimplementations. Equals.Fody is doing this for you, but after the compiler runs. To suppress the false-positives you can either do so- per project, by adding
<PropertyGroup><NoWarn>CS0660;CS0661</NoWarn></PropertyGroup>to the project file - per source file, by adding
#pragma warning disable CS0660, CS0661.
- per project, by adding
- implementing a custom hash code method (marked by
[CustomGetHashCode]) is optional.
public class Point : IEquatable<Point>
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
bool CustomLogic(Point other)
{
return Z == other.Z || Z == 0 || other.Z == 0;
}
public static bool operator ==(Point left, Point right)
{
return object.Equals((object)left, (object)right);
}
public static bool operator !=(Point left, Point right)
{
return !object.Equals((object)left, (object)right);
}
static bool EqualsInternal(Point left, Point right)
{
return left.X == right.X && left.Y == right.Y && leftt.CustomLogic(right);
}
public virtual bool Equals(Point right)
{
return !object.ReferenceEquals((object)null, (object)right) && (object.ReferenceEquals((object)this, (object)right) || Point.EqualsInternal(this, right));
}
public override bool Equals(object right)
{
return !object.ReferenceEquals((object)null, right) && (object.ReferenceEquals((object)this, right) || this.GetType() == right.GetType() && Point.EqualsInternal(this, (Point)right));
}
public override int GetHashCode()
{
return unchecked(this.X.GetHashCode() * 397 ^ this.Y.GetHashCode());
}
}
public class CustomGetHashCode : IEquatable<CustomGetHashCode>
{
public int X { get; set; }
public int Z { get; set; }
int CustomGetHashCodeMethod()
{
return 42;
}
static bool EqualsInternal(CustomGetHashCode left, CustomGetHashCode right)
{
return left.X == right.X;
}
public override bool Equals(CustomGetHashCode other)
{
return !object.ReferenceEquals(null, other) && (object.ReferenceEquals(this, other) || CustomGetHashCode.EqualsInternal(this, other));
}
public override bool Equals(object obj)
{
return !object.ReferenceEquals(null, obj) && (object.ReferenceEquals(this, obj) || (base.GetType() == obj.GetType() && CustomGetHashCode.EqualsInternal(this, (CustomGetHashCode)obj)));
}
public override int GetHashCode()
{
return (this.X.GetHashCode() * 397) ^ this.CustomGetHashCodeMethod();
}
public static bool operator ==(CustomGetHashCode left, CustomGetHashCode right)
{
return object.Equals(left, right);
}
public static bool operator !=(CustomGetHashCode left, CustomGetHashCode right)
{
return !object.Equals(left, right);
}
}Through properties on the [Equals] attribute the following options can be set:
DoNotAddEqualityOperators=> do not weave==and!=operatorsDoNotAddGetHashCode=> do not override theint GetHashCode()methodsDoNotAddEquals=> do not override thebool Equals(object other)method, do not add and implementIEquatable<T>IgnoreBaseClassProperties=> equality and hash code do not consider properties of base classes.TypeCheckcan be used to affect the equality logic.ExactlyTheSameTypeAsThis(default): only equal, when the other object is of the same type asthis. Imagine we have a classFoowith[Equals]and we have a sub-class Bar : Foo:Foomay equalFooBarmay equalBar- but
Foomay never equalBar
ExactlyOfType: only equal, when the other object is of the same as the method is added to. Consider a classFoowith[Equals(TypeCheck = ExactlyOfType)]and a sub-class Bar : Foo:Foomay equalFooBarmay never equalBarFoomay never equalBar
EqualsOrSubtype: equal, when the other object is of same type as the method is added to, or is of a sub type.
Icon courtesy of The Noun Project