IEnumerable <T>.ConvertAll & DDD - PullRequest
       33

IEnumerable <T>.ConvertAll & DDD

2 голосов
/ 08 января 2010

У меня есть интересная потребность в методе расширения интерфейса IEumerable - то же самое, что List.ConvertAll. Это было рассмотрено до здесь , и я нашел одно решение здесь . Что мне не нравится в этом решении, так это то, что он создает список для хранения преобразованных объектов, а затем возвращает его. Я подозреваю, что LINQ не был доступен, когда он написал свою статью, поэтому моя реализация такова:

public static class IEnumerableExtension
{
    public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Func<T, TOutput> converter)
    {
        if (null == converter)
            throw new ArgumentNullException("converter");

        return from item in collection
               select converter(item);
    }
}

Что мне больше всего нравится в этом, так это то, что я конвертирую «на лету», не загружая весь список значений TOutput. Обратите внимание, что я также изменил тип делегата - с Converter на Func. Компиляция такая же, но я думаю, что это проясняет мои намерения - я не хочу, чтобы это было ТОЛЬКО преобразование типов.

Что приводит меня к моему вопросу: на моем уровне хранилища у меня много запросов, которые возвращают списки идентификаторов - идентификаторы сущностей. Раньше у меня было несколько классов, которые «преобразовывали» эти идентификаторы в сущности различными способами. С помощью этого метода расширения я могу свести все это к следующему коду:

IEnumerable<Part> GetBlueParts()
{
    IEnumerable<int> keys = GetBluePartKeys();
    return keys.ConvertAll<Part>(PartRepository.Find);
}

где «конвертер» - это метод поиска по идентификатору хранилища. В моем случае «конвертер» потенциально делает совсем немного. Кто-нибудь видит какие-либо проблемы с этим подходом?

Ответы [ 2 ]

10 голосов
/ 08 января 2010

Основная проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что он совершенно не нужен.

Ваш метод ConvertAll ничем не отличается от Enumerable.Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>), который является стандартным оператором LINQ. Нет причин писать метод расширения для чего-то, что уже находится в фреймворке.

Вы можете просто сделать:

IEnumerable<Part> GetBlueParts() 
{ 
    IEnumerable<int> keys = GetBluePartKeys(); 
    return keys.Select<int,Part>(PartRepository.Find); 
} 

Примечание: вашему методу также потребуется <int,Part> для компиляции, если PartRepository.Find не работает только с int и возвращает только экземпляры Part. Если вы хотите избежать этого, вы можете сделать:

IEnumerable<Part> GetBlueParts() 
{ 
    IEnumerable<int> keys = GetBluePartKeys(); 
    return keys.Select(i => PartRepository.Find<Part>(i)); // I'm assuming that fits your "Find" syntax...
} 
1 голос
/ 08 января 2010

Почему бы не использовать ключевое слово yield (и конвертировать каждый элемент только по мере необходимости)?

public static class IEnumerableExtension
{
    public static IEnumerable<TOutput> ConvertAll<T, TOutput>
        (this IEnumerable<T> collection, Func<T, TOutput> converter)
    {
        if(null == converter)
            throw new ArgumentNullException("converter");

        foreach(T item in collection)
            yield return converter(item);
    }
}
...