Update: from .NET 4.5 onwards there is IReadOnlyList<out T>
and IReadOnlyCollection<out T>
which are both covariant; The latter is basically IEnumerable<out T>
plus Count
; the former adds T this[int index] {get;}
. It should also be noted that IEnumerable<out T>
is covariant from .NET 4.0 onwards.
Both List<T>
and ReadOnlyCollection<T>
(via List<T>.AsReadOnly()
) implement both of these.
It can only be covariant if it only has a get
indexer, i.e.
public T this[int index] { get; }
But all main collections have {get;set;}
, which makes that awkward. I’m not aware of any that would suffice there, but you could wrap it, i.e. write an extension method:
var covariant = list.AsCovariant();
which is a wrapper around an IList<T>
that only exposes the IEnumerable<T>
and the get
indexer…? should be only a few minutes work…
public static class Covariance
{
public static IIndexedEnumerable<T> AsCovariant<T>(this IList<T> tail)
{
return new CovariantList<T>(tail);
}
private class CovariantList<T> : IIndexedEnumerable<T>
{
private readonly IList<T> tail;
public CovariantList(IList<T> tail)
{
this.tail = tail;
}
public T this[int index] { get { return tail[index]; } }
public IEnumerator<T> GetEnumerator() { return tail.GetEnumerator();}
IEnumerator IEnumerable.GetEnumerator() { return tail.GetEnumerator(); }
public int Count { get { return tail.Count; } }
}
}
public interface IIndexedEnumerable<out T> : IEnumerable<T>
{
T this[int index] { get; }
int Count { get; }
}