Why is this an issue?
The foreach
statement was introduced in the C# language prior to generics to make it easier to work with the non-generic collections
available at that time such as ArrayList
. The foreach
statements allows you to downcast elements of a collection of
Object
s to any other type. The problem is that to achieve the cast, the foreach
statements silently performs
explicit
type conversion, which at runtime can result in an InvalidCastException
.
C# code iterating on generic collections or arrays should not rely on foreach
statement’s silent explicit
conversions.
Noncompliant code example
public class Fruit { }
public class Orange : Fruit { }
public class Apple : Fruit { }
class MyTest
{
public void Test()
{
var fruitBasket = new List<Fruit>();
fruitBasket.Add(new Orange());
fruitBasket.Add(new Orange());
// fruitBasket.Add(new Apple()); // uncommenting this line will make both foreach below throw an InvalidCastException
foreach (Fruit fruit in fruitBasket)
{
var orange = (Orange)fruit; // This "explicit" conversion is hidden within the foreach loop below
...
}
foreach (Orange orange in fruitBasket) // Noncompliant
{
...
}
}
}
Compliant solution
var fruitBasket = new List<Orange>();
fruitBasket.Add(new Orange());
fruitBasket.Add(new Orange());
// fruitBasket.Add(new Apple()); // uncommenting this line won't compile
foreach (Orange orange in fruitBasket)
{
...
}
or
var fruitBasket = new List<Fruit>();
fruitBasket.Add(new Orange());
fruitBasket.Add(new Orange());
fruitBasket.Add(new Apple());
foreach (Orange orange in fruitBasket.OfType<Orange>())
{
...
}
Exceptions
The rule ignores iterations on collections of object
s. This includes legacy code that uses ArrayList
. Furthermore, the
rule does not report on cases when user defined conversions are being called.