Для ответа на этот вопрос надо окунуться в историю. А именно был момент, когда не было Generic-типизации и был только нетипизированный интерфейс перечисления IEnumerable. А потом с приходом новой версии .Net появились обобщения (это когда явно указывается тип <T>
, в твоем случае тип данных <Product>
).
Сигнатура этого интерфейса выглядит следующим образом:
public interface IEnumerable<out T> : IEnumerable
То есть для обратной совместимости, новый интерфейс наследует старый, а значит и метода нужно реализовать два: один, который возвращает старый нетипизированный вариант, и новый, более удобный типизированный вариант.
Для понимания: в старом варианте, когда ты обходил в цикле каждый элемент через foreach - тип элемента был object (все другие типы от него унаследованы). И на каждой итерации, чтобы получить свой тип Product и работать с ним - приходилось делать приведение типов.
В новом варианте, благодаря тому, что явно указан тип <Product>
при обходе в цикле - ты сразу получаешь объект типа Product.
Рекомендую по этой теме почитать вообще изменения в .Net при переходах с версии на версию + почитать про Generic в дотнете.