Подтвердить что ты не робот

Foreach может вызывать InvalidCastException?

Представьте следующий код:

class foreach_convert
{
    public static void method2()
    {
        List<IComparable> x = new List<IComparable>();
        x.Add(5);

        foreach (string s in x)
        {
            //InvalidCastException in runtime
        }
    }
}

Интересно, почему это поведение foreach так... не похоже на С#? Что происходит здесь, это неявный приведение к подклассу, который подвержен ошибкам и, кажется, запрещен в любом другом месте на этом языке. Или я не прав?

P.S. Причина, по которой я спрашиваю, заключается в том, что у меня была ошибка в аналогичном коде в моем проекте, где я использовал для итерации через пользовательскую коллекцию из внешней библиотеки, которая называлась как SomeTypeCollection, но на самом деле предоставлялась коллекция базовых и могли содержать элементы SomeOtherType. Моя ошибка, но все же ни язык, ни компилятор не предоставили никаких явных подсказок/предупреждений, что довольно необычно для С#...

4b9b3361

Ответ 1

Вспомните перед дженериками... foreach должен был сделать так, чтобы вы могли делать такие вещи, как:

foreach (string x in names)
{
    // ...
}

вместо:

foreach (object tmp in names)
{
    string x = (string) tmp;
    // ...
}

Последнее просто нехорошо, ИМО. Предоставление неявного литья в отличие от остальной части языка, но делает его намного проще в использовании в подавляющем большинстве случаев.

Я подозреваю, что если у С# были общие методы и методы расширения, чтобы начать (чтобы мы могли использовать OfType и Cast), что foreach не будет указываться совершенно таким же образом.

Обратите внимание, что в foreach еще больше нечетности: тип вообще не должен реализовывать IEnumerable. До тех пор, пока у него есть метод GetEnumerator, который возвращает что-то, что в свою очередь имеет MoveNext() и Current, компилятор С# счастлив. Это означало, что вы могли бы реализовать "строго типизированный итератор" (чтобы избежать бокса) до дженериков.

Ответ 2

С С# 3 я использую var - поэтому я получаю предупреждения компилятора.

Ответ 3

foreach работает над IEnumerable, который возвращает объекты типа object. Для каждого элемента объект будет передан в тип, который вы указали.

Если вы не используете var в С# 3.0. Тогда тип будет заимствован из IEnumerable<T>, если он будет реализован в коллекции.