C #, objectCollection.OfType <T>() и foreach (T item в objectCollection), IEnumerable в IEnumerable <T> - PullRequest
5 голосов
/ 19 мая 2011

Моему личному стилю кодирования принадлежит Enumerable.OfType<T>(). Я использую его везде, это имеет смысл. Особенно IEnumerable<T> допускает мощную функцию linqToObject. Я ненавижу "небезопасное" зацикливание ObjectCollections, как примеры ниже. Теперь у меня есть несколько вопросов о циклической обработке этих «UnGenericCollections».

Вопрос 1: Если я преобразую это ArrayList в Enumerable<T>, насколько велик дополнительный цикл по сравнению с простым циклом foreach / if-check?

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 ]

2 голосов
/ 20 мая 2011

Чтобы не допустить повторения коллекции дважды и сохранить какой-то приятный синтаксис, я бы предложил метод расширения, который позволяет связывать 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

2 голосов
/ 19 мая 2011

Вы не найдете никакой разницы, поскольку ArrayList реализует IEnumerable. На самом деле, все, что реализует этот интерфейс, может использоваться в выражении foreach.

При сотворении объекта вместо установки var будет построено (поскольку это явное приведение), но если внутри перечисления есть животное, вам придется столкнуться с исключениями приведения.

foreach (Animal animal in ark) { } // this will blow up an exception if the object is Human
2 голосов
/ 19 мая 2011

Ответ 1:

В вашем примере - вы, возможно, итерируете по перечисляемому FULL дважды.

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

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

Ответ 2:

Будет выдано исключение InvalidCastException, если в ковчеге есть не человек.

Я бы лично предпочел ark.OfTypes<T>(), если я знаю, что хочу иметь дело только с Human и Animals, но проигнорирую Elves. Таким образом, код становится намного чище, и вы имеете дело со строго типизированным объектом в цикле foreach.

Но опять же, если я не хочу игнорировать Elves, я бы предпочел повторить полный ArrayList и использовать приведение.

0 голосов
/ 19 мая 2011

Enumerable.OfType пройдёт по всем элементам и выполнит проверку is T для Вас. Таким образом, каждый OfType вызов будет повторяться по всем элементам в коллекции. Это должно быть медленнее. Но это другое дело, если это будет медленнее, не стоит делать это в своей программе.

Я бы подумал, если есть смысл помещать объекты классов, у которых нет одного и того же родителя, в одну коллекцию. Возможно, вы могли бы найти некоторую абстракцию, а затем в foreach привести все объекты к базовому классу и использовать полиморфные вызовы.

...