17

I have a HashSet and I am trying to cast it into IReadOnlyCollection, but I am getting error:

Cannot implicitly convert type 'System.Collections.Generic.HashSet' to 'System.Collections.Generic.IReadOnlyCollection'. An explicit conversion exists (are you missing a cast?)

Hashset is a

public class HashSet<T> : ICollection<T>, ISerializable, IDeserializationCallback, ISet<T>, IReadOnlyCollection<T>

I can use explicit cast, but I don't know the reason why I can't just use it as IReadOnlyCollection.

HashSet<DateTime> set = new HashSet<DateTime> { DateTime.Today };
ICollection<DateTime> collection = set; // OK
ISerializable serializable = set;       // OK
IDeserializationCallback deserializationCallback = set; // OK
ISet<DateTime> iSet = set;                              // OK
IReadOnlyCollection<DateTime> castReadOnlyCollection = (IReadOnlyCollection<DateTime>)set; // OK
IReadOnlyCollection<DateTime> readOnlyCollection = set; // Error

Why can't I use it without an explicit cast?

I am using .NET framework 4.5

Wesley Lomax
  • 2,067
  • 2
  • 20
  • 34
jahav
  • 699
  • 1
  • 7
  • 24
  • And apparently it did not always implement that interface http://stackoverflow.com/questions/11849861/why-hashsett-does-not-implement-ireadonlycollectiont – juharr Sep 24 '15 at 13:32
  • It was an oops in .NET 4.5, induced by IReadOnlyCollection<> being added to support the WinRT language projection and WinRT not having an equivalent of a set. It got fixed in 4.5.1, simply change your project's framework target as a workaround. – Hans Passant Sep 24 '15 at 13:37

2 Answers2

27

You're using 4.5 and Hashset doesn't implement IReadOnlyCollection until 4.6

From MSDN:

HashSet implements the IReadOnlyCollection interface starting with the .NET Framework 4.6; in previous versions of the .NET Framework, the HashSet class did not implement this interface.

https://msdn.microsoft.com/en-us/library/bb359438(v=vs.110).aspx

rmn36
  • 656
  • 4
  • 12
  • 6
    At the top of the page it says ".NET Framework 4.6 and 4.5", so I didn't expect changes in API. That is not the case, good to know. Thanks. – jahav Sep 24 '15 at 13:48
  • 3
    Thus is the world of documentation. Some are better than others but all will inevitably have their inaccuracies, unfortunately. – rmn36 Sep 24 '15 at 13:57
12

This is because in .NET 4.5, HashSet<T> doesn't implement IReadOnlyCollection<T>. In .NET 4.6, it does, so the implicit cast works as expected.

BTW, the explicit cast in your code snippet compiles, but it will fail at runtime. It compiles because the set variable is of type HashSet<DateTime>, and since HashSet<DateTime> is not sealed, there might be subclasses that implement the interface.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Thanks, I have probably another weird issue there. Project says Framework 4.5, but R# test with cast succeeds (unit tests should use target platform of a project). – jahav Sep 24 '15 at 13:44