Closed erri120 closed 1 year ago
I've gone with adding a new parameter, e.g.:
[ValueObject(stringComparison: StringComparison.OrdinalIgnoreCase)]
This makes sense when applied to a class
, but I'm wondering what to do if the attribute is applied to a record
as that implements its own equality etc.
Any suggestions welcomed.
I wanted this for IComparable<T>
as well.
What if Vogen just doesn't generate the related methods when it's already defined in the original class/struct, does that work?
In terms of records and equality, it's still possible to override those: https://sharplab.io/#v2:D4AQTAjAsAUCDMACATgUwMYHtkBNEEEAKASwDsAXRANQEpEBvWRZxBRAN2OXIFcBDADaIARpkxCAogEd+AgM6F8AfkSZyAC1TI6AXgB8qjVqUA6Koh07qAbiYs7zNpnZbkxHKkRlKAcVTkACT45dQBhTA9CXQMqEz9A4LCI1CjbGABfWCy4JDlUQVQ8NCxcRAAhEgpqOkYYFlYkUXFEaVkFMpU1TW0LAy7jMwsrKjT6hwbVF2Q3Dy8q+KCQ8Mjo6jj/RaSVtPSgA
Whilst implementing this, I went down the rabbit hole of modifying the generated code for Equals
and GetHashCode
to automatically use the EqualityComparer
based on the provided value (e.g. OrdinalIgnoreCase
).
But with hindsight, I now think Value Objects that wrap strings should just expose the equality comparer it generates and also generate overrides for Equals
and GetHashCode
with a StringComparison
argument.
This is now implemented. You can now specify a new parameter in local or global config specifying whether to generate string comparers, e.g.
[ValueObject<string>(stringComparers: StringComparersGeneration.Generate)]
public partial class MyVo
{
}
It's an enum with options Omit
and Generate
. It defaults to Omit
.
If it's set to Generate
, then it generates a bunch of comparers which can use in Equals
or collections, e.g.
var left = MyVo.From("abc");
var right = MyVo.From("AbC");
var comparer = MyVo.Comparers.OrdinalIgnoreCase;
left.Equals(right, comparer).Should().BeTrue();
... and in a dictionary
Dictionary<MyVo, int> d = new(MyVo.Comparers.OrdinalIgnoreCase);
MyVo key1Lower = MyVo.From("abc");
MyVo key2Mixed = MyVo.From("AbC");
d.Add(key1Lower, 1);
d.Should().ContainKey(key2Mixed);
Also generated is an Equals method that takes an IEqualityComparer<>
:
public bool Equals(MyVo other, IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}
Please let me know if this works OK for you!
Describe the feature
When using
ValueObject<string>
, the various equality and compare methods are using the default equality comparer. This is fine for most types, however, strings are different since you can compare a string usingOrdinal
andOrdinalIgnoreCase
, which drastically changes equality.Since you can't override the generated methods, the only solution at the moment is using a custom implementation of
IEqualityComparer<TValueObject>
whereTValueObject
has theValueObject<string>
attribute:Ideally, there should be an option that allows you to specify the comparer:
You'd still need a custom implementation of
IEqualityComparer
, sinceStringComparer.OrdinalIgnoreCase
is a static get-only property, so it can't really be used in the attribute.