Перечислить Generic GetEnumerator, приведение к интерфейсу, не удается

Приведение GetEnumerator к интерфейсу не работает.
Нет ошибки компилятора.
Ошибка выполнения с бесконечностью индекса сообщения.
Если я использую структуру Word1252 напрямую, без интерфейса, она работает

namespace WordEnumerable
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            WordEnum wordEnum = new WordEnum();
            Debug.WriteLine(wordEnum[0].GetType().ToString());
            Debug.WriteLine(wordEnum[0].Value);
            Debug.WriteLine(wordEnum.Count.ToString());
            foreach (iWord w in wordEnum)  // fails here
            {
            }
        }
    }
}
public interface iWord
{
    Int32 Key { get; }
    String Value { get; }
}
public class WordEnum : IEnumerable<iWord>
{
    private static List<Word1252> words1252 = new List<Word1252>();
    IEnumerator<iWord> IEnumerable<iWord>.GetEnumerator()
    {
        return ((IEnumerable<iWord>)words1252).GetEnumerator();
    }
    public struct Word1252 : iWord
    {
        public UInt64 packed;
        public Int32 Key   { get { return (Int32)((packed >> 27) & ((1 << 25) - 1)); } }
        public Byte Length { get { return (Byte) ((packed >> 59) & ((1 <<  5) - 1)); } }
        public String Value { get { return Key.ToString(); } }
        public Word1252(UInt64 Packed) { packed = Packed; }
    }

person paparazzo    schedule 20.04.2013    source источник


Ответы (1)


Короче говоря, это upcasting от IEnumerable<Word1252> до IEnumerable<IWord>,

А для этого требуется covariance.

Несмотря на то, что IEnumerable помечен как out (ковариантный)
Ковариация не работает для «типов значений» - то есть структуры, которую вы определили в интерфейсе.

например видеть...

Является ли это ошибкой ковариации в C # 4?
(или немного другое, но сводится к той же проблеме)
Почему IEnumerable ‹struct› не может быть преобразован как IEnumerable ‹object›?

Чтобы решить эту проблему, вы можете просто определить свой список, например

private static List<iWord> words1252 = new List<iWord>();  

Или определите свой перечислитель следующим образом:

IEnumerator<iWord> IEnumerable<iWord>.GetEnumerator()
{
    foreach (var word in words1252)
        yield return word;
}
person NSGaga-mostly-inactive    schedule 20.04.2013
comment
Они оба работали, спасибо. С частным статическим списком ‹iWord› слова1252 = новый список ‹iWord› (); Мне пришлось преобразовать в Word1252 для внутренних вещей, но я возьму это. Вы знаете, есть ли у foreach снижение производительности? Если нет, я бы предпочел это использовать. - person paparazzo; 21.04.2013
comment
пожалуйста. foreach лучше согласен. Здесь нет никакого влияния на производительность (или в лучшем случае некоторые дополнительные операции) - он `` уступает '', так как он в основном делает то же самое, что и исходный `` перечислитель '' - это известный и принятый метод `` приведения '' в `` Перечислители '' (например, когда вам нужно вернуть другой элемент, но не можете применить) - person NSGaga-mostly-inactive; 21.04.2013