开发者

foreach(Derived obj in new List<Base>())

开发者 https://www.devze.com 2023-01-19 13:35 出处:网络
What does the following code do? class Base { } class Derived : Base { } cl开发者_如何学Cass Test {

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 type E and element type T. A foreach statement of the form

foreach (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:

  1. Instantiate a new List, with zero items
  2. Iterate over that newly instantiated list, which has zero items
  3. 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.
  4. 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消