C#, objectCollection.OfType<T>() and foreach (T item in objectCollection), IEnumerable to IEnumerable<T>
To my personal coding style belongs Enumerable.OfType<T>()
. I use it everywhere it makes a little bit of sense. Especially IEnumerable<T>
allows mighty linqToObject functionallity. I hat开发者_开发技巧e the "type-unsafe" looping of ObjectCollections such as the samples below. Now I have some questions about looping across these "UnGenericCollections".
ConfigurationSectionCollection
HttpModuleCollection
SPBaseCollection
SPFieldCollection
ArrayList
- so on...
Question 1: If I convert this ArrayList
to Enumerable<T>
how big is the additional loop in comparison with the simple foreach/if-checks?
var ark = new ArrayList();
ark.Add(new Human());
ark.Add(new Human());
ark.Add(new Animal());
Instead of:
foreach (object passenger in ark)
{
if (passanger is Human) { }
if (passanger is Animal) { }
}
I use:
foreach (var human in ark.OfType<Human>())
{
}
foreach (var animal in ark.OfType<Animal>())
{
}
Question 2: During a foreach loop into a different typed variable, which way of casting/converting will be used? Is this a language feature or does that work out of the box?
foreach (Human human in ark) { }
Thanks for enduring my awful English. Best regards,Benjamin
Ans 1:
In your sample - you may actually be iterating over the FULL enumerable twice.
// i use
foreach (var human in ark.OfType<Human>())
{
}
foreach (var animal in ark.OfType<Animal>())
{
}
Ans 2:
It would throw an InvalidCastException exception if there are any non-human in ark.
I would personally prefer ark.OfTypes<T>()
, in case I know I only want to deal with Human
and Animals
but would be ignoring Elves
. This way code is much more cleaner and you are dealing with strongly typed object in your foreach loop.
But again in case I do not want to ignore Elves
, I would take rather iterate thru full ArrayList and use casts.
You'll find no difference since ArrayList implements IEnumerable. Actually, anything that implements this interface may be used in a foreach statement.
Casting the object instead of setting up a var will build (since it's an explicit cast) but if you have an animal inside the enumeration, you'll end up having to deal with casting exceptions.
foreach (Animal animal in ark) { } // this will blow up an exception if the object is Human
To prevent the collection from being iterated two times and to keep some kind of sweet syntax, I'd come with a extension method that allows chaining foreachs for specified types. I thought it would be funny:
static void Main(string[] args)
{
var ugly = new ArrayList();
ugly.Add("strings are evil");
ugly.Add("yeah");
ugly.Add(1);
ugly.Add(3);
ugly.Add(1234);
ugly.WithType<int>(x => Console.WriteLine("im a lousy int! " + x))
.AndType<string>(x => Console.WriteLine("and im dangerous string: " + x))
.Execute();
Console.ReadKey();
}
static TypedCollectionView WithType<T>(this IEnumerable x, Action<T> action)
{
return new TypedCollectionView(x).AndType(action);
}
class TypedCollectionView
{
private readonly IEnumerable collection;
private readonly Dictionary<Type, Action<object>> actions = new Dictionary<Type, Action<object>>();
public TypedCollectionView(IEnumerable collection)
{
this.collection = collection;
}
public TypedCollectionView AndType<T>(Action<T> action)
{
actions.Add(typeof(T), o => action((T)o));
return this;
}
public void Execute()
{
foreach (var item in collection)
{
var itemType = item.GetType();
foreach (var action in actions.Where(kv.Key.IsAssignableFrom(itemType)).Select(kv.Value))
{
action(item);
}
}
}
}
so.. now how to make this suck less? :D
Enumerable.OfType
will go over all elements and do the is T
check for You. So every OfType
call will iterate over all elements in collection. That must be slower. But it's other thing if it's slower to the point You shouldn't do it in Your program.
I would think If there is a point in putting objects of classes that don't have same parent in one collection. Maybe You could find some abstraction and then in foreach cast all objects to base class and use polymorphic calls.
精彩评论