Исключение при попытке привести IEnumerable? - PullRequest
4 голосов
/ 16 декабря 2011

Первые пару недель я все еще изучаю C # для проекта и пытаюсь правильно реализовать интерфейс IEnumerable. Я прочитал несколько руководств / руководств, но, похоже, все еще что-то делаю неправильно. У меня сильный опыт работы с Java, поэтому я думаю, что некоторые из моих знаний об обобщениях Java мешают мне понять, как они работают в C #.

Класс, который Я не могу изменить содержит переменную экземпляра:

public IEnumerable<object> Items;

И я хотел бы предоставить ему экземпляр моего SampleDataSource класса. Этот класс действует как контейнер для хранения типов List из MyObject:

    public class SampleDataSource : IEnumerable
    {
        public List<MyObject> Subjects { get; private set; }

        public IEnumerator<MyObject> GetEnumerator()
        {
            return this.Cast<MyObject>().GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

Но когда я пытаюсь привести экземпляр этого SampleDataSource класса к IEnumerable<object>, используя этот код:

Items = (IEnumerable<MyObject>)App.SampleData;

Я получаю исключение:

Дополнительная информация: невозможно привести объект типа 'Expression.Blend.SampleData.SampleDataSource.SampleDataSource' для тип 'System.Collections.Generic.IEnumerable`1 [Expression.Blend.SampleData.SampleDataSource.MyObject].

Но я не совсем понимаю, почему - мой SampleDataSource не действует должным образом как IEnumerable, который возвращает перечислитель, содержащий MyObject типов?

Ответы [ 2 ]

6 голосов
/ 16 декабря 2011

Он не может просто реализовывать методы, а должен фактически реализовывать интерфейс.

В вашем случае было бы лучше просто заставить ваш класс реализовать соответствующий интерфейс.

public class SampleDataSource : IEnumerable<MyObject>, IEnumerable

В противном случае вы можете использовать что-то вроде linfu для ввода вашего класса в интерфейс.

Другой потенциальный объект - использовать OfType<T> длясправиться с этим:

// returns enumerable of the items that are actually assignable to MyObject
IEnumerable<MyObject> values = theDataSource.OfType<MyObject>();
1 голос
/ 17 декабря 2011

Я понимаю, что на вопрос уже дан ответ, но я упустил простое объяснение проблемы, стоящей за вашим вопросом, поэтому вот так:

Причина, по которой вы не можете присвоить свой класс SampleDataSource полю IEnumerable<object>, заключается в том, что SampleDataSource не реализует IEnumerable<object>. Хотя он реализует IEnumerable, этого недостаточно, потому что IEnumerable<object> является подтипом из IEnumerable.

Из-за ковариации интерфейса вы сможете присвоить класс полю IEnumerable<object>, если оно реализует IEnumerable<MyObject>, при условии, что MyObject на самом деле является ссылочным типом (то есть классом) , Однако это применимо только к C # 4.0 и более поздним версиям.

В ответе Рида Копси не упоминается, что вы могли бы объявить класс SampleDataSource таким образом, потому что IEnumerable<T> наследуется от IEnumerable:

public class SampleDataSource : IEnumerable<MyObject>

Далее, поскольку вы просто оборачиваете вложенную коллекцию, вы обычно реализуете ее следующим образом:

public class SampleDataSource : IEnumerable<MyObject>
{  
    public List<MyObject> Subjects { get; private set; }  

    public IEnumerator<MyObject> GetEnumerator()  
    {  
        return Subjects.GetEnumerator();
    }  

    IEnumerator IEnumerable.GetEnumerator()  
    {  
        return GetEnumerator();  
    }  
}  

Это сомнительно с точки зрения объектной ориентации, поскольку вы предоставляете общественности доступ для чтения и записи к списку. (Тот факт, что установщик является частным, означает, что общедоступный не может переназначить ссылку на список, но это не мешает им вызывать Add или Remove или Clear в списке.)

Еще один вопрос об ориентации объекта будет заключаться в следующем: если SampleDataSource содержит последовательность MyObjects, почему он также будет последовательностью MyObjects? Вместо этого:

classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;

Может быть, вы должны делать это:

classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;
...