Question

I am using the HashSet collection type which has already significantly improved the performance of my algorithm. It seems that each time I invoke myHashSet.Contains(someValue) the internal implementation is boxing the value type immediately before invoking Equals.

Is there a way to avoid these wasteful allocations when using value types?

Sample Code:

public struct TestStruct {
    public int a;
    public int b;

    public override int GetHashCode() {
        return a ^ b;
    }

    public override bool Equals(object obj) {
        if (!(obj is TestStruct))
            return false;
        TestStruct other = (TestStruct)obj;
        return a == other.a && b == other.b;
    }
}

var hashset = new HashSet<TestStruct>();
PopulateSet(hashset);

// About to go crazy on the allocations...
if (hashset.Contains(someValue)) { ... }
// Lots of allocations just happened :(
Was it helpful?

Solution

After a lucky guess it looks like the answer is just to implement the IEquatable<T> interface like demonstrated below. HashSet<T> (or at least the Mono implementation) then takes an allocation-free approach to its Contains method by using a different comparer implementation.

public struct TestStruct : IEquatable<TestStruct> {
    ...

    public bool Equals(TestStruct other) {
        return a == other.a && b == other.b;
    }
}

// No more pain!
if (hashset.Contains(someValue)) { ... }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top