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
}
精彩评论