В чем разница между ((IEnumerable)source).OfType<T>()
и source as IEnumerable<T>
Для меня они похожи, но это не так!
Вы правы. Они очень разные.
Первое означает «взять исходную последовательность и создать совершенно новую, отличающуюся последовательность, состоящую из всех элементов данного типа из предыдущей последовательности».
Последнее означает «если тип времени выполнения исходной последовательности имеет заданный тип, тогда дайте мне ссылку на эту последовательность, в противном случае дайте мне ноль».
Позвольте мне проиллюстрировать это примером. Предположим, у вас есть:
IEnumerable<Animal> animals = new Animal[] { giraffe, tiger };
IEnumerable<Tiger> tigers = animals.OfType<Tiger>();
Это вернет вам новую, отличающуюся последовательность, содержащую одного тигра.
IEnumerable<Mammal> mammals = animals as IEnumerable<Mammal>;
Это даст вам ноль. Животные - это НЕ последовательность млекопитающих, даже если это последовательность животных, которые оказываются только млекопитающими. Фактический тип животных во время выполнения - это «набор животных», а набор животных не совместим по типу с последовательностью млекопитающих. Почему бы и нет? Хорошо, предположим, что преобразование сработало, и вы тогда сказали:
animals[0] = snake;
Mammal mammal = mammals.First();
И, эй, вы просто поместили змею в переменную, которая может содержать только млекопитающее! Мы не можем этого допустить, поэтому преобразование не работает.
В C # 4 вы можете пойти другим путем. Вы можете сделать это:
IEnumerable<Object> objects = animals as IEnumerable<Object>;
потому что массив животных может рассматриваться как последовательность объектов. Вы помещаете туда змею, а змея все еще является объектом. Это работает только в C # 4. (И это работает, только если оба типа являются ссылочными типами. Вы не можете превратить массив int в последовательность объектов.)
Но главное, что нужно понять, это то, что метод OfType<T>
возвращает совершенно новую последовательность , а оператор "as" выполняет проверку типа времени выполнения . Это совершенно разные вещи.
Вот еще один способ взглянуть на это.
tigers = animals.OfType<Tiger>()
в основном совпадает с
tigers = animals.Where(x=>x is Tiger).Select(x=>(Tiger)x);
То есть создайте новую последовательность, выполнив проверку каждого члена животных, чтобы выяснить, является ли это тигром. Если это так, бросьте его. Если это не так, откажитесь от него.
mammals = animals as IEnumerable<Mammal>
, с другой стороны, в основном совпадает с
if (animals is IEnumerable<Mammal>)
mammals = (IEnumerable<Mammal>) animals;
else
mammals = null;
Имеет смысл?