リストの読み取り専用のインデックス可能な「ビュー」を作成したかったのですが、読み取り専用ビューがリスト型のインターフェイスに列挙する必要があるというわずかなひねりがあります。
interface IIndexable<out T> : IEnumerable<T>
{
T this[int i] { get; }
int Count { get; }
}
使用シナリオは次のようになります。
List<Dog> dogs = new List<Dog>[]{ dog1, dog2 }; // Dog implements IAnimal
IIndexable<IAnimal> animals = dogs.AsIIndexable<Dog, IAnimal>();
IAnimal first = animals[0];
共分散と型の制約があればこれは可能だと思いましたが、ここで間違っているかもしれません。私の最初の試みは次のようになりますが、列挙子のタイプが原因で機能しません。
internal class ListIndexable<TC, T> : IIndexable<T> where TC : T
{
private List<TC> list;
public ListIndexable(List<TC> list) { this.list = list; }
public T this[int i] { get { return list[i]; } }
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator(); // Computer says no.
}
}
IEnumerator<TC>
をとして返すことができないのはなぜIEnumerator<T>
ですか? 型は共変であり、私はそれを TC : T で制約しました。 を返すのは本当に安全ではないでしょうかIEnumerator<TC>
、それともコンパイラの推論が型制約を無視するのは単にここでの弱点ですか?
IEnumerator<TC>
をラップしてその項目を として返すカスタム列挙子を使用することで解決できますが、T
これはもちろん完全に合法ですが、上記の解決策が機能しない理由が知りたいです。
internal class ListIndexable<TC, T> : IIndexable<T> where TC : T
{
private List<TC> list;
public ListIndexable(List<TC> list) { this.list = list; }
public T this[int i] { get { return list[i]; } }
public IEnumerator<T> GetEnumerator()
{
return new Enumerator(list.GetEnumerator());
}
class Enumerator : IEnumerator<T>
{
private IEnumerator<TC> inner;
internal Enumerator(IEnumerator<TC> inner) { this.inner = inner; }
public bool MoveNext()
{
return inner.MoveNext();
}
public T Current
{
get { return inner.Current; }
}
// ...
}
}