2016-11-22 2 views
0

У меня есть три спискаConcat Список <type> где списки могут быть нулевыми

List<Project> intProjects = ProjectRepo.GetAllInternalProjects(); 
List<Project> extProjects = ProjectRepo.GetAllExternalProjects(); 
List<Project> mgmProjects = ProjectRepo.GetAllManagementProjects(); 
List<Project> projects = intProjects.Concat(extProjects).Concat(mgmProjects).ToList(); 

Если у меня есть пункты во всех списках он работает нормально, но я получать null value исключения, когда один из списков null.

Да, я мог бы сделать

if (extProjects != null && mgmpProjects != null && intProjects != null) 
    ... 
else if (extProjects == null && mgmpProjects != null && intProjects != null 
    ... 

для всех возможных случаев, но должно быть более эффективным способом объединить списки, даже если они являются недействительными.

Итак, мой вопрос: как я могу составить списки, где списки могут быть пустыми, не получая ошибку?

+4

Использование Concat (extProjects ?? новый Список ()) – Evk

ответ

5

Вы могли бы сделать что-то вроде этого с помощью оператора ??:

List<Project> empty = new List<Project>(); 
List<Project> intProjects = ProjectRepo.GetAllInternalProjects() ?? empty; 
List<Project> extProjects = ProjectRepo.GetAllExternalProjects() ?? empty; 
List<Project> mgmProjects = ProjectRepo.GetAllManagementProjects() ?? empty; 
List<Project> projects = intProjects.Concat(extProjects).Concat(mgmProjects).ToList(); 

?? Operator (C# Reference)

+0

'Enumerable.Empty ()' будет отражать намерение лучше. – Xiaoy312

1

Внутри вашего ProjectRepo убедитесь, что функции GetAllInternalProjects(), GetAllExternalProjects(), GetAllManagementProjects() все возвращают пустой список, если не найдено. Для функций, возвращающих списки, я инициализирую возвращаемое значение в начале функции, а затем при необходимости делаю что-то в этом списке и всегда возвращаю это значение. Таким образом, функция всегда будет возвращать объект списка, пустой или непустой. Это должно очистить ваш код.

Пример ниже:

List<object> GetAllInternalProjects(){ 
    List<object> results = new List<object>(); 

    /do something here 

    return results; 

} 
1

Не обязательно эффективно, но не требует много печатать:

List<Project> projects = new[] { intProjects, extProjects, mgmProjects } 
         .Where(list => list != null) 
         .SelectMany(_ => _) 
         .ToList(); 
3

Вы можете использовать метод расширения как этот

public static class EnumerableExtension 
{ 
    public static IEnumerable<TSource> ConcatOrSkipNull<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 
    { 
     if (first == null) 
      first = new List<TSource>(); 
     if (second == null) 
      return first; 
     return first.Concat(second); 
    } 
} 

и перепишите код, а затем:

var projects = intProjects 
        .ConcatOrSkipNull(extProjects) 
        .ConcatOrSkipNull(mgmProjects) 
        .ToList(); 
+0

Отличная идея! Я бы предложил два незначительных изменения: (1) Пропустить проверку «first == null». Просто сделайте частью контракта этого метода, что его операция не определена, если вызвана нулевой ссылкой для параметра this. (2) Не уверен, что 'ConcatOrDefault' - хорошее имя. С LINQ '... OrDefault' обычно означает, что« null »может быть возвращен, что здесь не так. Как насчет 'ConcatOrSource',' ConcatOrOriginal', 'ConcatOrSelf' и т. Д. – stakx

+1

@stakx - Спасибо за ваши мысли. Я включил проверку 'first-null', из-за заявленной проблемы OP. Что касается (2): Именование - действительно сложная задача. Теперь я придумал'ConcatOrSkipNull'. Но я думаю, что по-прежнему возможно лучшее именование ... –

+0

Я стою исправлен (1)! – stakx

1

Другой возможностью является метод расширения как

public static partial class EnumerableExtensions { 
    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source) { 
     return source ?? Enumerable.Empty<T>(); 
    } 
    } 

Таким образом, вы можете поместить

List<Project> projects = intProjects 
    .EmptyIfNull() 
    .Concat(extProjects.EmptyIfNull()) 
    .Concat(mgmProjects.EmptyIfNull()) 
    .ToList(); 

Лучше подход необходимости модифицировать GetAllInternalProjects(), GetAllExternalProjects() и ProjectRepo.GetAllManagementProjects() методы: эти методы должны всегда возвращать неnull сбор (который может быть пустой, однако)

Смежные вопросы