Reputation: 68466
With the first foreach
in the below example, I'm sure it should throw a compilation error, but they build fine. Issues only occur at run time when it throws an invalid cast exception (as you'd expect):
public interface IState
{
int Id { get; }
string Description { get; }
}
public class Dog
{
public string Name { get; set; }
public string Breed { get; set; }
}
public class Cat
{
public string Name { get; set; }
public string Breed { get; set; }
}
public void Foo()
{
IEnumerable<IState> states = new List<IState>();
foreach (Dog dog in states) { } // Does not break in the compiler
IEnumerable<Cat> cats = new List<Cat>();
foreach (Dog dog in cats) { } // Obviously breaks in compiler
}
Why does this get passed the compiler? Dog
is completely unrelated to IState
, and if I tried to iterate through a list of Cat
instead then the compiler will obviously catch it.
Upvotes: 3
Views: 70
Reputation: 1500385
The compiler is implicitly converting a cast from the element type to the type you've specified in the foreach
statement.
So if you have an IEnumerable<Foo>
and you use it as:
foreach (Bar bar in foos)
then that will insert a cast from Foo
to Bar
. This will compile if and only if that cast would normally be valid.
It isn't valid to cast from Cat
to Dog
because they're unrelated types. A Cat
reference can never be valid as a Dog
reference.
If is valid to cast from IState
to Dog
because it could be valid:
public class DogState : Dog, IState
{
public int Id => 5;
public string Description => "Dog state!";
}
IState state = new DogState();
Dog dog = (Dog) state; // Won't throw
In your collection example:
IEnumerable<IState> states = new List<IState> { new DogState() };
foreach (Dog dog in states)
{
Console.WriteLine("I've got a dog state!");
}
Upvotes: 3