I have an ILookup<int, Derived> and I want to return an ILookup<int, Base> where Derived implements or extends Base.
Currently I use SelectMany() and then ToLookup() to first extract the key value pairs of ILookup<int, Derived> into a flat IEnumerable and then create a new ILookup<int, Base>:
class Base { }
class Derived: Base { }
class Test
{
ILookup<int, Base> CastLookup(ILookup<int, Derived> existing)
{
IEnumerable<KeyValuePair<int, Base>> flattened = existing.SelectMany(
(x) => x,
(gr, v) => new KeyValuePair<int, Base>(gr.Key, (Base)v)); // I know the explicit cast can be implicit here; it is just to demonstrate where the up casting is happening.
ILookup<int, Base> result = flattened.ToLookup(
(x) => x.Key,
(x) => x.Value);
return result;
}
}
How can I convert an ILookup without iterating its entries and then repacking them?
NOTE: A related question is Shouldn't ILookup<TKey, TElement> be (declared) covariant in TElement? by bigge. Ryszard Dżegan answers that it is mostly for historical reasons: ILookup<TKey, TElement> has been developed before generics with covariance.
Herzmeister asks something similar for a Dictionary<TKey, TValue>. Mehrdad Afshari answers that for the mutable dictionary the covariance would not be safe.
Indeed, if Ilookup<TKey, TElement> was covariant in TElement, I would not have run into this instance of the ILookup<TKey, TElement> casting question; but it is not, so my quest for a better way still continues.
NOTE: I can of course write an extension method to do it, but that does not prevent the required computational work of iterating and repacking.