开发者

Objects of a specific type in foreach from an IEnumerable

开发者 https://www.devze.com 2023-03-30 18:51 出处:网络
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 m

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();
fo开发者_JAVA技巧reach (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?


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"


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.


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


Short cast in ForEeach:

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

精彩评论

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