C#,objectCollection.OfType <t>()和foreach(objectCollection中的T项),IEnumerable到IEnumerable <t> </t> </t>

时间:2011-05-19 18:50:44

标签: c# foreach ienumerable linq-to-objects generic-list

我的个人编码风格属于Enumerable.OfType<T>()。我在任何地方使用它都有点意义。特别是IEnumerable<T>允许强大的linqToObject功能。我讨厌ObjectCollections的“类型不安全”循环,例如下面的示例。现在我有一些关于循环这些“UnGenericCollections”的问题。

问题1:如果我将此ArrayList转换为Enumerable<T>与简单的foreach / if-checks相比,附加循环有多大?

var ark = new ArrayList();
ark.Add(new Human());
ark.Add(new Human());
ark.Add(new Animal());

而不是:

foreach (object passenger in ark)
{
    if (passanger is Human) { }
    if (passanger is Animal) { }
}

我用:

foreach (var human in ark.OfType<Human>())
{
}

foreach (var animal in ark.OfType<Animal>())
{
}

问题2:在foreach循环中使用不同类型的变量,将使用哪种投射/转换方式?这是一种语言功能还是开箱即用?

foreach (Human human in ark) { }

感谢您忍受我可怕的英语。最好的问候,本杰明

4 个答案:

答案 0 :(得分:2)

答案1:

在您的示例中 - 您实际上可能会迭代 FULL 两次。

// i use
foreach (var human in ark.OfType<Human>())
{
}

foreach (var animal in ark.OfType<Animal>())
{
}

答案2:

如果ark中存在任何非人类,则会抛出InvalidCastException异常。

我个人更喜欢ark.OfTypes<T>(),如果我知道我只想处理HumanAnimals,但会忽略Elves。这样代码更清晰,你在foreach循环中处理强类型对象。

但是,如果我不想忽略Elves,我会通过完整的ArrayList重复迭代并使用强制转换。

答案 1 :(得分:2)

你会发现没有区别,因为ArrayList实现了IEnumerable。实际上,任何实现此接口的东西都可以在foreach语句中使用。

转换对象而不是设置var将构建(因为它是显式转换)但是如果在枚举中有动物,则最终必须处理转换异常。

foreach (Animal animal in ark) { } // this will blow up an exception if the object is Human

答案 2 :(得分:2)

为了防止集合被迭代两次并保留某种甜蜜的语法,我会提供一个扩展方法,允许为指定类型链接foreach。 我觉得这很有趣:

    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);
                }
            }
        }
    }

所以..现在如何减少这个? :d

答案 3 :(得分:0)

Enumerable.OfType将检查所有元素并执行is T检查。因此,每个OfType调用都将遍历集合中的所有元素。那一定要慢一些。但是如果它更慢到达你的程序就不应该这样做了。

我认为如果在一个集合中放置没有相同父类的类的对象是有意义的。也许你可以找到一些抽象,然后在foreach中将所有对象转换为基类并使用多态调用。