>
>
>
V3087. Type of variable enumerated in '…


V3087. Type of variable enumerated in 'foreach' is not guaranteed to be castable to the type of collection's elements.

Анализатор обнаружил потенциальную ошибку в цикле 'foreach'. Существует вероятность возникновения исключения InvalidCastException при обходе коллекции 'IEnumarable<T>'.

Рассмотрим пример:

List<object> numbers = new List<object>();
....
numbers.Add(1.0);
....
foreach (int a in numbers)
  Console.WriteLine(a);

В данном случае, шаблон коллекции 'numbers' инициализирован типом 'object', тем самым позволяя добавлять в неё объекты любого типа.

При обходе этой коллекцией, в цикле задано, что её члены должны иметь тип 'int'. Если в коллекции окажется объект другого типа, будет выполнено приведение и возможно возникновение исключения 'InvalidCastException'. В нашем примере исключение возникнет из-за невозможности распаковки (Unboxing) значения типа 'double', упакованного в элементе типа 'object' коллекции, в тип 'int'.

Для исправления данной ошибки можно привести тип шаблона коллекции и тип элемента в цикле 'foreach' к одному типу:

Вариант 1:

List<object> numbers = new List<object>();
....
foreach (object a in numbers)

Вариант 2:

List<int> numbers = new List<int>();
....
foreach (int a in numbers)

Часто подобная ошибка наблюдается, когда имеется коллекция с элементами базового интерфейса, а в цикле указывают тип одного из интерфейсов или классов, реализующих данный базовый интерфейс:

void Foo1(List<ITrigger> triggers){
  ....
  foreach (IOperableTrigger trigger in triggers)
  ....
}
void Foo2(List<ITrigger> triggers){
  ....
  foreach (IMutableTrigger trigger in triggers)
  ....
}

Для обхода в коллекции объектов только одного конкретного типа, можно предварительно отфильтровать её с помощью функции 'OfType':

void Foo1(List<ITrigger> triggers){
  ....
  foreach (IOperableTrigger trigger in
    triggers.OfType<IOperableTrigger>())
  ....
}
void Foo2(List<ITrigger> triggers){
  ....
  foreach (IMutableTrigger trigger in 
    triggers.OfType<IMutableTrigger>())
  ....
}

Такой код гарантирует, что цикл foreach будет работать только с объектами нужного типа, и исключит возможность возникновения исключения 'InvalidCastException'.

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V3087.