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 typeFirstAttributeto 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
foreachstatement 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
eis not visible to or accessible to the expressionxor the embedded statement or any other source code of the program. The variablevis read-only in the embedded statement. If there is not an explicit conversion (§10.3) fromT(the iteration type) toV(the _local_variabletype in theforeachstatement), 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
FirstAttributetoSecondAttribute
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.
