Explicit type conversion in C# foreach loop
If you are a C# programmer, I am sure you use foreach
loops regularly and believe you are well acquainted with this language construct. So do you think the following code can be compiled?
var attributes = typeof(MyClass).GetCustomAttributes(typeof(FirstAttribute), false);
foreach (SecondAttribute attribute in attributes)
{
//...
}
Well, it does compile. And then fails at runtime with the following exception:
System.InvalidCastException
: 'Unable to cast object of typeFirstAttribute
to typeSecondAttribute
.'
Let us try to explain. The GetCustomAttributes
method returns an instance of object[]
. The array contains instances of FirstAttribute
. In the foreach
loop, the compiler performs an explicit conversion from object
to SecondAttribute
, which fails at runtime because there is no conversion from FirstAttribute
to SecondAttribute
. Essentially, the above code is the same as the following:
foreach (var attribute in attributes)
{
SecondAttribute secondAttribute = (SecondAttribute)attribute;
//...
}
This is definitely not something you see every day, especially with the widespread use of generics today. But this behavior is fully documented in the C# specification, as cited below:
A
foreach
statement of the form
foreach (V v in x) «embedded_statement»
is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try
{
while (e.MoveNext())
{
V v = (V)(T)e.Current;
«embedded_statement»
}
}
finally
{
... // Dispose e
}
}
The variable
e
is not visible to or accessible to the expressionx
or the embedded statement or any other source code of the program. The variablev
is read-only in the embedded statement. If there is not an explicit conversion (§10.3) fromT
(the iteration type) toV
(the _local_variabletype in theforeach
statement), an error is produced and no further steps are taken.
This is just another potential pitfall of using the object
type, since there is an explicit conversion from object
to any other (reference) type.
The best way to avoid the runtime error with the above code is to use the generic extension method GetCustomAttributes
instead of the non-generic member method:
using System.Reflection;
var attributes = typeof(MyClass).GetCustomAttributes<FirstAttribute>(false);
foreach (SecondAttribute attribute in attributes)
{
//...
}
The above code will not compile with the following compiler error:
CS0030: Cannot convert type
FirstAttribute
toSecondAttribute
This would certainly be enough to notice the wrong type of iteration variable and change it. Or even better, use an implicitly typed variable with the var
keyword:
foreach (var attribute in attributes)
{
//...
}
I put an example project in my GitHub repository. The individual commits correspond to each of the approaches described above.
Using the object
type instead of generics has many dangers, most of them related to runtime errors due to explicit type conversion. But while you can usually spot explicit type conversions in code as cast expressions, that's not the case in the foreach
loop, which makes it even easier to miss them. The safest thing you can do is to avoid the object
type and use generics as often as possible.