2017-04-11 12 views
7

Uprościliśmy kod odroczonego kodu wykonawczego, ale jak to się stało, że nie jest puste/puste, bez pakowania w try/catch?Testowanie dla "leniwego załadowanego" null IEnumerable in C#?

string[] nullCollection = null; 
    IEnumerable<string> ienumerable = new[] { nullCollection }.SelectMany(a => a); 

    bool isnull = ienumerable == null; //returns false 
    bool isany = ienumerable.Any(); //throws an exception 
+0

@MrinalKamboj Jest to wyjątek NullReferenceException, ponieważ SelectManyIterator jest wywoływany z elementem zerowym. –

+0

@RB. wtedy jest to podchwytliwe, żaden z powyższych punktów nie będzie się trzymał –

Odpowiedz

3

Wystarczy dokonać lambda bardziej odporne na pozycji zerowych:

IEnumerable<string> ienumerable = new[] { nullCollection } 
    .SelectMany(a => a ?? Enumerable.Empty<string>()); 

bool isany = ienumerable.Any(); // Sets isany to 'false' 
+0

To jest miłe, ale jeśli po prostu przekazałem argument "IEnumerable ", to chyba utknąłem ... – maxp

+0

@maxp Yep - jest fundamentalny problem z konstrukcją 'ienumerable'. Nie sądzę, żeby to naprawiło. –

2

Można sprawdzić, czy aktualna pozycja z wyliczający jest null

string[] nullCollection = null; 
IEnumerable<string> ienumerable = new[] { nullCollection }.SelectMany(a => a); 

bool isnull = ienumerable.GetEnumerator().Current == null; 
if (!isnull) 
{ 
    bool isany = ienumerable.Any(); 
} 
+1

To nie zadziała - gdy wywołasz 'MoveNext()' do iteracji przez to zawiedzie, jeśli natknie się na element 'null'. Ostatecznie funkcja projekcji zostanie oceniona dla każdego elementu i spowoduje awarię, gdy zostanie wywołana z wartością pustą - nie sądzę, żeby to się udało. –

+2

@RB. W/o 'MoveNext()', nie ma 'Current' :). Czy jest z powrotem do kwadratu One –

+3

To jest dość niepoprawna odpowiedź - dostęp do 'Current' przed' MoveNext' ma niezdefiniowane zachowanie - najprawdopodobniej tutaj zawsze zwraca 'null'. –

3

Nie można tego zrobić , ponieważ to jest to samo, co pytanie "jak mogę stwierdzić, że metoda nie rzuci NullReferenceException bez wywoływania go?". Nie mając innych wskazówek, jedynym sposobem jest wywoływanie takich metod i obserwowanie wyniku. Wyliczanie IEnumerable wywołuje tylko kilka wywołań MoveNext na jego wyliczniku, a każde takie wywołanie może zgłaszać wszelkie wyjątki.

0

Ponieważ metody Linq są metodami rozszerzenia na IEnumerable, można zawijać te rozszerzenia dalej: z metodą rozszerzenia obiekt otrzymujący rozszerzenie może mieć wartość null.

public static IEnumerable<TResult> SafeSelectMany<T, TCollection, TResult>(
      this IEnumerable<T> source, 
      Func<T, IEnumerable<TCollection>> collectionSelector, 
      Func<T, TCollection, TResult> resultSelector) 
    { 
     if (source == null) 
     { 
      return null; 
     } 
     IEnumerable<TResult> result = source.SelectMany(collectionSelector, resultSelector); 
     return result; 
    } 

Można również powrócić pusty List<TResult> zamiast null dla source==null.