我想要一个可以通过索引检索其项目的Covariant集合。IEnumerable是我所知道的唯一的.net集合是Covariant,但是它没有此索引支持。
具体来说,我想这样做:
List<Dog> dogs = new List<Dog>(); IEnumerable<Animal> animals = dogs; IList<Animal> animalList = dogs; // This line does not compile
现在,我知道了为什么这是一个问题。列出ICollection具有Add方法的实现。通过强制转换IList为Animals,它将允许后续代码添加“真实” List<Dog>集合中不允许的任何类型的动物。
ICollection
IList
List<Dog>
那么,有谁知道一个集合也支持协变量的索引查找?我不想创建自己的。
更新:从.NET 4.5开始IReadOnlyList<out T>,IReadOnlyCollection<out T>这两者都是协变的;后者基本上是IEnumerable<out T>加号Count; 前者补充说T this[int index] {get;}。还应注意,IEnumerable<out T>从.NET 4.0开始是协变的。
IReadOnlyList<out T>
IReadOnlyCollection<out T>
IEnumerable<out T>
Count
T this[int index] {get;}
双方List<T>并ReadOnlyCollection<T>(通过List<T>.AsReadOnly())实现这两个。
List<T>
ReadOnlyCollection<T>
List<T>.AsReadOnly()
如果只有get索引器,则只能是协变的,即
get
public T this[int index] { get; }
但是所有主要收藏都有{get;set;},这很尴尬。我不知道有什么可以满足要求的,但是您可以 将 其 包装 起来,即编写一个扩展方法:
{get;set;}
var covariant = list.AsCovariant();
这是一个包装器IList<T>,仅暴露IEnumerable<T>和和get索引器…?应该只有几分钟的工作…
IList<T>
IEnumerable<T>
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; } }