Reputation: 37660
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 :
List<MyClass>
and add new methods. This will leave the .Add and .Remove as is and can cause troubles for consumer codeICollection<MyClass>
. Create an internal Dictionary<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 valuesI'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())
{
}
}
Upvotes: 3
Views: 146
Reputation: 437366
HashSet<MyClass>
is a good fit for your usage case because it models your intent and can be configured with a custom IEqualityComparer<MyClass>
(thus it doesn't matter that MyClass
does not implement IEquatable<MyClass>
).
Unfortunately HashSet
does not implement IList
, 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?
Upvotes: 2