Let’s say I have a class like this :
public class MyClass {
public int Id { get; set;}
public string Name { get; set; }
}
Please note that this class, in my case, is out of control (from a 3rd party library) and does not implement equality comparers.
Now I want to have a collection of this items that allow me to remove items based on their index.
I’m expecting to be able to do :
void Foo()
{
var collection = new MyClassCollection();
var a = new MyClass { Id = 1, Name = "A" };
var b = new MyClass { Id = 2, Name = "B" };
collection.Add(a);
collection.Add(b);
// Other instance, that can come from external code
var otherA = new MyClass { Id = 1, Name = "A" };
var otherB = new MyClass { Id = 2, Name = "B" };
collection.Remove(otherA);
Console.WriteLine(collection.Count); // should output 1
Console.WriteLine(collection.Contains(otherB)); // should be true
collection.Add(otherB); //
Console.WriteLine(collection.Count); // should still output 1
}
In fact, only the ID should be considered when searching within the collection. This code is part of a project that rely on serialized DTO, and thus, cannot rely on instances.
How should I implement MyClassCollection?
I think about two possibilities, but neither looks like elegant for me :
- inherits from
List<MyClass>and add new methods. This will leave the .Add and .Remove as is and can cause troubles for consumer code - Create a class that implements
ICollection<MyClass>. Create an internalDictionary<int, MyClass>to store the values, and use the dictionary builtin features to check keys before adding or removing. Implement all methods of the interface by wrapping the internal dictionary values
I’d appreciate your point of view regarding my case.
PS: I expect to have very few elements in the list (<100 items). Performance won’t be an issue
Edit: I’m using .Net 3.5 SP1.
Edit2: according Jon advise, here is my implementation :
public class MyClassCollection : HashSet<MyClass>
{
private class MyClassIDComparer : IEqualityComparer<MyClass>{
public bool Equals(MyClass x, MyClass y)
{
if (x == null && y == null) return true;
else if (x == null || y == null) return false;
else return x.ID == y.ID;
}
public int GetHashCode(MyClass obj)
{
return obj.ID.GetHashCode();
}
}
public MyClassCollection() : base(new MyClassIDComparer())
{
}
}
HashSet<MyClass>is a good fit for your usage case because it models your intent and can be configured with a customIEqualityComparer<MyClass>(thus it doesn’t matter thatMyClassdoes not implementIEquatable<MyClass>).Unfortunately
HashSetdoes not implementIList, so it cannot directly do index-based access — but do you really need that? Perhaps this requirement can be relaxed by rethinking some part of your business logic?