70 lines
2.7 KiB
Plaintext
70 lines
2.7 KiB
Plaintext
== Why is this an issue?
|
|
|
|
The https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement[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 https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist[ArrayList]. The `foreach` statements allow you to downcast elements of a collection of https://learn.microsoft.com/en-us/dotnet/api/system.object[Objects] to any other type.
|
|
|
|
The problem is that to achieve the cast, the `foreach` statements silently perform https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#explicit-conversions[explicit type conversion], which at runtime can result in an https://learn.microsoft.com/en-us/dotnet/api/system.invalidcastexception[InvalidCastException].
|
|
|
|
C# code iterating on generic collections or arrays should not rely on `foreach` statement's silent `explicit` conversions.
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
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());
|
|
|
|
foreach (Orange orange in fruitBasket) // Noncompliant
|
|
{
|
|
//...
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
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());
|
|
|
|
foreach (Orange orange in fruitBasket.OfType<Orange>())
|
|
{
|
|
//...
|
|
}
|
|
}
|
|
}
|
|
|
|
----
|
|
|
|
=== Exceptions
|
|
|
|
The rule ignores iterations on collections of `objects`. This includes legacy code that uses `ArrayList`. Furthermore, the rule does not report on cases when user-defined conversions are being called.
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement[Foreach statement]
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist[ArrayList]
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.object[Object class]
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#explicit-conversions[Explicit conversion]
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.invalidcastexception[InvalidCastException]
|
|
|
|
include::../rspecator.adoc[] |