# 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.