foreach(Derived obj in new List<Base>())
What does the following code do?
class Base { }
class Derived : Base { }
cl开发者_如何学Cass Test
{
void Foo(List<Base> list)
{
foreach (Derived obj in list)
{
// ...
}
}
}
I didn't expect it to even compile, but it does.
The behavior you are observing is according to section 8.8.4 The foreach statement of the C# language specification. This section defines the semantics of the foreach
statement as follows:
[...] The above steps, if successful, unambiguously produce a collection type
C
, enumerator typeE
and element typeT
. Aforeach
statement of the formforeach (V v in x) embedded-statement
is then expanded to:
{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { // here the current item will be casted v = (V)(T)e.Current; embedded-statement } } finally { // Dispose e } }
The reason that the compiler inserts this explicit cast is historic. C# 1.0 didn't have generics so in order to allow simple code like this
ArrayList list = new ArrayList();
list.Add(1);
foreach (int i in list)
{
...
}
it was decided to let the compiler introduce the cast.
Absolutely nothing, but it does it in a very inefficient manner.
The order of operations is this:
- Instantiate a new List, with zero items
- Iterate over that newly instantiated list, which has zero items
- Not cast the Base object to a Derived object, because the list has zero items. If the list had any items, this step would result in a runtime exception.
- Not execute the code in the foreach block, because the list has zero items.
Edit
Based on your edit, you run the risk of an InvalidCastException
should any element of the list passed to Foo
not actually be a Derived
object.
Edit2
Why does it compile? Because foreach
involves an implicit cast to Object
for each item in the list, then another explicit cast to the specified type in the foreach
block, in this case Derived
foreach
includes a cast. Consider that it can be used with non-templated enumerations of objects. Casting from Base
to Derived
is valid, so the code is valid, but could throw an exception at runtime.
Not sure why would not expect this to compile. Consider this, which is functionally equivalent:
{
List<Base> list = new List<Base>(); // creates new, empty list of Base
foreach (Derived obj in list)
{
// ...
}
}
Does that make it clearer what's going on in your code?
EDIT re revised version.
Now it will throw InvalidCastException if your list contains anything that is not an instance of Derived. Derived 'is a' Base so still no issue with compiling this.
Technically, Randolpho is correct: your code does nothing. But I think you're getting at a different point.
Casting your list items to Derived
will give you access to properties defined in the Derived
class in addition to the properties defined in the Base
class. However, you'll get errors if you have items not of type Derived
in the list when you access those properties.
Barring some other need, you're better off having the list defined as List<Derived>
.
the same as
list.Cast<Derived>();
it just type casting. in some case u might got error
It is equivalent to:
Enumerator<Base> enumerator = new List<Base>().GetEnumerator();
while (enumerator.MoveNext())
{
Derived obj = (Derived) enumerator.Current;
// ...
}
As your list is empty, the inner block does not execute.
Were it to contain elements, then there would be the risk of a InvalidCastException
should any of the elements not be of type Derived
.
精彩评论