JSBձոգչ
JSBձոգչ

Reputation: 41378

Objects of a specific type in foreach from an IEnumerable

I'm working with a legacy collection object that only implements non-generic IEnumerable and ICollection. What exactly happens with this object when I try to use this object with a foreach giving a more specific type on the LHS of the foreach expression?

// LegacyFooCollection implements non-generic IEnumerable
LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection)
{
    // etc.
}

I know (because I've tried it) that this is safe when everything in collection really is of type Foo, but what happens if that fails?

Upvotes: 11

Views: 21741

Answers (4)

Suplanus
Suplanus

Reputation: 1601

Short cast in ForEeach:

foreach (MenuItem menuItem in treeView.ContextMenu.Items.Cast<object>().OfType<MenuItem>()
{
    // Do stuff
}

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500365

The C# compiler performs the cast implicitly for you. In terms of the casting (but only in those terms1) it's equivalent to:

foreach (object tmp in collection)
{
    Foo f = (Foo) tmp;
    ...
}

Note that this will happen with generic collections too:

List<object> list = new List<object> { "hello", "there", 12345 };

// This will go bang on the last element
foreach (string x in list) 
{
}

This is all detailed in section 8.8.4 of the C# 4 spec.

If you're using .NET 3.5 or higher and you want to only select items of the appropriate type, you can use Enumerable.OfType:

LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection.OfType<Foo>())
{
    // etc.
}

That may not be necessary for a LegacyFooCollection, but it can be useful when you're trying to find (say) all the TextBox controls in a form.


1 The differences are:

  • In your original code, f is read-only; in the "conversion" it's writable
  • In your original code, if you capture f you will (currently) capture a single variable across all iterations, as opposed to a separate variable per iteration in the "conversion"

Upvotes: 21

cdhowie
cdhowie

Reputation: 168998

This code will create a runtime type conversion (cast) of each element of the enumerable to Foo. So, if you did foreach (string f in collection) you would get a ClassCastException at runtime, the first time it tries to convert a Foo reference to a String reference.

Upvotes: 4

Yuriy Faktorovich
Yuriy Faktorovich

Reputation: 68667

It will be casting each time. The foreach loop is just using the IEnumerator methods.

Upvotes: 0

Related Questions