Closed aradalvand closed 2 months ago
Collections aren't supported because they don't exhibit value semantics. For instance, a Hash.From([1, 2, 3]) == Hash.From([1, 2, 3])
is false.
Also, serialization probably wouldn't work for collections, e.g. when [ValueObject<IEnumerable<byte>>]
and instantiating with `Hash.From([1,2,3]) (an array)
An alternative is to use a "deep-equatable" array, and have that as the underlying type for a value object. Here is such an array implementation:
You can then do:
[ValueObject<ImmutableEquatableArray<byte>>]
Actually, that won't work either, as it delves into the hierarchy to see if it's a collection.
This works, kinda:
public class Hash<T> : IEquatable<T> where T : IEquatable<T>
{
private readonly ImmutableEquatableArray<T> _items;
public Hash(T[] items) => _items = items.ToImmutableEquatableArray();
protected bool Equals(Hash<T> other) => _items.Equals(other._items);
public bool Equals(T? other) => _items.Equals(other);
public override bool Equals(object? obj) => _items.Equals(obj);
public override int GetHashCode() => _items.GetHashCode();
public static implicit operator Hash<T>(T[] items) => new(items);
}
[ValueObject<Hash<byte>>]
public readonly partial struct FileHash;
The only reason it doesn't currently work is that Vogen emits incorrect triple-slash comments when the underlying type is a generic - which I'll fix soon.
To be honest, I'm now re-thinking the whole thing of constraining the underlying type so that it can't be a collection.
Leave this with me, and I'll think it over again. Thanks for your input, and if you have any thoughts or suggestions on this topic, please let us know.
Also, for array, I don't know what ToString
would do by default...
Also, for array, I don't know what ToString would do by default...
I think for all collections you could just do something sensible like $"[{string.Join(", ", Value)}]"
After careful consideration, I've left the restriction on ICollection
, purely because it enables an easy way to mutate the data in the value object, which Vogen goes to considerable lengths (via the analyzers) to stop.
However, you can achieve the same result by using an intermediary underlying type that wraps your collection. I've added an example test to demonstrate.
Thanks for reporting - please let me know if you need any further assistance or clarification
purely because it enables an easy way to mutate the data in the value object, which Vogen goes to considerable lengths (via the analyzers) to stop.
@SteveDunn Wouldn't it be feasible then to only allow immutable collection types (e.g. ImmutableArray<T>
)?
Describe the bug
Array types don't work apparently:
Repro:
Also, the README claims that "any type can be wrapped", which does not actually seem to be true.
Repro:
Am I missing something?
Steps to reproduce
Outlined above.
Expected behaviour
Should just work.