Explicit type conversion in C# foreach loop

November 11th 2022 C#

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 type FirstAttribute to type SecondAttribute.'

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 expression x or the embedded statement or any other source code of the program. The variable v is read-only in the embedded statement. If there is not an explicit conversion (§10.3) from T (the iteration type) to V (the _local_variabletype in the foreach 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 to SecondAttribute

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.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License