RSCG – Valuify
| name | Valuify |
| nuget | https://www.nuget.org/packages/Valuify/ |
| link | https://github.com/MooVC/valuify |
| author | Paul Martins |
Generating Equals from properties
This is how you can use Valuify .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Valuify" Version="1.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
The code that you will use is
// See https://aka.ms/new-console-template for more information
using GeneratorEqualsDemo;
var p1 = new Person()
{
ID = 1,
FirstName = "Andrei",
LastName = "Ignat"
};
var p2= new Person()
{
ID = 1,
FirstName = "Andrei",
LastName = "Ignat"
};
Console.WriteLine(p1==p2);
namespace GeneratorEqualsDemo;
[Valuify.Valuify]
partial class Person
{
public int ID { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
The code that is generated is
namespace Valuify
{
using System;
using System.Diagnostics.CodeAnalysis;
[AttributeUsage(AttributeTargets.Class,Inherited = false,AllowMultiple = false)]
internal sealed class ValuifyAttribute
: Attribute
{
}
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public static bool operator ==(Person left,Person right)
{
if (ReferenceEquals(left,right))
{
return true;
}
if (ReferenceEquals(left,null) || ReferenceEquals(right,null))
{
return false;
}
return global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(left.ID,right.ID)
&& global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(left.FirstName,right.FirstName)
&& global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(left.LastName,right.LastName);
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public sealed override bool Equals(object other)
{
return Equals(other as Person);
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public sealed override int GetHashCode()
{
return global::Valuify.Internal.HashCode.Combine(ID,FirstName,LastName);
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public bool Equals(Person other)
{
return this == other;
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
: IEquatable<Person>
{
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public static bool operator !=(Person left,Person right)
{
return !(left == right);
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace GeneratorEqualsDemo
{
using System;
using System.Collections.Generic;
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable disable
#endif
partial class Person
{
public sealed override string ToString()
{
return string.Format("Person { ID = {0},FirstName = {1},LastName = {2} }",ID,FirstName,LastName);
}
}
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
#nullable restore
#endif
}
namespace Valuify.Internal
{
using System;
using System.Collections;
internal static class HashCode
{
private const int HashSeed = 0x1505;
private const int HashPrime = -1521134295;
public static int Combine(params object[] values)
{
int hash = HashSeed;
foreach (object value in values)
{
if (value is IEnumerable && !(value is string))
{
IEnumerable enumerable = (IEnumerable)value;
foreach (object element in enumerable)
{
hash = PerformCombine(hash,element);
}
}
else
{
hash = PerformCombine(hash,value);
}
}
return hash;
}
private static int PerformCombine(int hash,object value)
{
int other = GetHashCode(value);
unchecked
{
return (other * HashPrime) + hash;
}
}
private static int GetHashCode(object value)
{
int code = 0;
if (value != null)
{
code = value.GetHashCode();
}
return code;
}
}
}
namespace Valuify.Internal
{
using System;
using System.Collections;
internal sealed class SequenceEqualityComparer
{
public static readonly SequenceEqualityComparer Default = new SequenceEqualityComparer();
public bool Equals(IEnumerable left,IEnumerable right)
{
if (ReferenceEquals(left,right))
{
return true;
}
if (ReferenceEquals(left,null) || ReferenceEquals(null,right))
{
return false;
}
return Equals(left.GetEnumerator(),right.GetEnumerator());
}
public int GetHashCode(IEnumerable enumerable)
{
return HashCode.Combine(enumerable);
}
private static bool Equals(IEnumerator left,IEnumerator right)
{
while (left.MoveNext())
{
if (!right.MoveNext())
{
return false;
}
if (!Equals(left.Current,right.Current))
{
return false;
}
}
return !right.MoveNext();
}
}
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Valuify
Leave a Reply