C#、objectCollection.OfType() 和 foreach(objectCollection 中的 T 项)、IEnumerable 到 IEnumerable

发布于 2024-11-08 20:18:28 字数 1728 浏览 0 评论 0原文

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

问题 1:如果我将此 ArrayList 转换为 Enumerable 与简单的 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) { }

谢谢你忍受我糟糕的英语。最好的问候,本杰明

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 hate the "type-unsafe" looping of ObjectCollections such as the samples below. Now I have some questions about looping across these "UnGenericCollections".

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深海夜未眠 2024-11-15 20:18:28

Ans 1:

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

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

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

Ans 2:

如果方舟中存在非人类,则会抛出 InvalidCastException 异常。

我个人更喜欢 ark.OfTypes(),以防我知道我只想处理 HumanAnimals 但会忽略精灵。这样代码更加简洁,并且您在 foreach 循环中处理强类型对象。

但同样,如果我不想忽略 Elves,我宁愿迭代完整的 ArrayList 并使用强制转换。

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.

落在眉间の轻吻 2024-11-15 20:18:28

由于 ArrayList 实现了 IEnumerable,因此您不会发现任何差异。实际上,任何实现此接口的东西都可以在 foreach 语句中使用。

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

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

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
叹沉浮 2024-11-15 20:18:28

为了防止集合被迭代两次并保持某种甜蜜的语法,我提供了一个扩展方法,允许链接指定类型的 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

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

ゞ花落谁相伴 2024-11-15 20:18:28

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文