Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support StringEqualityAttribute on collections of strings #60

Open
divega opened this issue Apr 22, 2024 · 1 comment
Open

Support StringEqualityAttribute on collections of strings #60

divega opened this issue Apr 22, 2024 · 1 comment
Labels
enhancement New feature or request

Comments

@divega
Copy link

divega commented Apr 22, 2024

While experimenting with Generator.Equals, I found that if I try to customize string equality to be case insensitive for a property that is for example an array of strings, the code generated by Generator.Equals will currently incorrectly assume the property is a string. GetHashCode code produces a compilation error:

CS0411: The type arguments for method 'HashCode.Add(T, IEqualityComparer?)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I assume the only way Generator.Equals can handle this case is via a custom equality, but I believe the case to be common enough to consider supporting it directly. Making StringEqualityAttribute handle it seems like it would be nice. Other than that, in general it would be nice if generation failed with a better error when an attribute is used with a member of an unsupported type.

Moreover, if I try to combine StringEqualityAttribute and UnorderedEqualityAttribute on the same property, generation will obey unordered equality and the intent to treat the string elements as case insensitive will be ignored. Personally I think this is also a compelling scenario to support.

Repro

using Generator.Equals;

Console.WriteLine("Hello, World!");

[Equatable]
public partial class Resource
{
    [StringEquality(StringComparison.OrdinalIgnoreCase)]
    public string[] Tags { get; set; } = Array.Empty<string>();

}

Generator.Equals will detect the attribute and generate code that assumes that the property is a string, for both the code generated for equality and the code generated for hash code:

    /// <inheritdoc/>
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Generator.Equals", "1.0.0.0")]
    protected bool Equals(global::Resource? other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        
        return other.GetType() == this.GetType()
            && global::System.StringComparer.OrdinalIgnoreCase.Equals(this.Tags!, other.Tags!)
            ;
    }
    
    /// <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.Tags!,
            global::System.StringComparer.OrdinalIgnoreCase
        );
        
        return hashCode.ToHashCode();
    }
@diegofrata
Copy link
Owner

The library is not very smart at detecting when the wrong attributes are used. You should be able to roll your own comparer for string collections and use it with the CustomEquality attribute. There are examples of CustomEquality in the README.

One way to potentially support this scenario is to extend the collection comparers to take an item comparer as an optional argument.

@diegofrata diegofrata added the enhancement New feature or request label Apr 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants