Я использовал для создания интерфейсов с IEnumerable<T>
в качестве возвращаемого типа, когда я хочу указать, что определенный вывод доступен только для чтения. Мне нравится, так как он минималистичный, скрывает детали реализации и отделяет вызываемого от вызывающего.
Но недавно мой коллега утверждал, что IEnumerable<T>
следует сохранить для сценариев, которые включают только ленивую оценку, так как в противном случае неясно для вызывающего метода, где обработка исключения должна иметь место - вокруг вызова метода или вокруг итерация. Тогда для активных случаев оценки с выходом только для чтения я должен использовать ReadOnlyCollection
.
Звучит вполне разумно для меня, но что бы вы посоветовали? Согласитесь ли вы с этим соглашением для IEnumerable? Или есть лучшие методы обработки исключений вокруг IEnumerable?
На всякий случай, если мой вопрос неясен, я сделал примерный класс, иллюстрирующий проблему. Два метода здесь имеют абсолютно одинаковую сигнатуру, но требуют разной обработки исключений:
public class EvilEnumerable
{
IEnumerable<int> Throw()
{
throw new ArgumentException();
}
IEnumerable<int> LazyThrow()
{
foreach (var item in Throw())
{
yield return item;
}
}
public void Run()
{
try
{
Throw();
}
catch (ArgumentException)
{
Console.WriteLine("immediate throw");
}
try
{
LazyThrow();
}
catch (ArgumentException)
{
Console.WriteLine("No exception is thrown.");
}
try
{
foreach (var item in LazyThrow())
{
//do smth
}
}
catch (ArgumentException)
{
Console.WriteLine("lazy throw");
}
}
}
Обновление 1. Вопрос не ограничивается только ArgumentException. Речь идет о передовых методах создания дружественных интерфейсов классов, которые сообщают вам, возвращают ли они ленивый оцененный результат или нет, поскольку это влияет на подход к обработке исключений.