2010-08-19 6 views
12

Jestem zmęczony z użyciem kodu:Powrót do zera dla count() na zerowych IEnumerables

var count = 0; 
if (myEnumerable != null) 
{ 
    count = myEnumerable.Count(); 
} 

I to jest nieco pedantyczny:

var count = (myEnumerable ?? new string[0]).Count(); 

Czy istnieje jakiś sposób porządniej robiąc to? Miałem kiedyś (źle nazwaną) metodę rozszerzenia PhantomCount na IEnumerable <> która wykorzystała mój pierwszy przykład kodu, ale miała w sobie coś z tego zapachu (poza nazwą).

Odpowiedz

30

Problem jest naprawdę cokolwiek tworzenia tych enumerables. Jeśli nie masz naprawdę dobrego powodu, wszystko, co generuje kolekcję iteracyjną, powinno zwrócić pustą kolekcję zamiast null. To byłoby zgodne z Null-Object-Pattern, stąd korzyści są takie same.

Moja sugestia będzie naprawić cokolwiek produkuje myEnumerable, lub jeśli nie można tego zrobić, dodać czek sposób wcześniej, aby sprawdzić, czy jest nieważna i odpowiednio reagować.

+12

+1 dla diagnozowania głównej przyczyny – cordialgerm

+0

Mieć kolejne +1. To naprawdę dobra praktyka przy projektowaniu interfejsu API w celu zwrócenia pustych kolekcji zamiast wartości zerowych, aby uniknąć nakładania na deweloperów ciężaru, aby takie testy były wykonywane przez cały czas. – uriDium

+0

Zależy. Istnieje różnica między listą wszystkich naprawdę dobrych win produkowanych w Irlandii (która jest pustą listą) a wszystkimi naprawdę dobrymi winami produkowanymi w Narnii (która jest zerowa, ponieważ Narnia nie istnieje). Czasami konieczne jest odróżnienie wartości pustej od pustej. Zgadzam się, że należy się jednak skłaniać ku powrotowi pustemu. –

13

Jak o

count = myEnumerable == null? 0 : myEnumerable.Count() 
+1

Mam wrażenie, że hes zamiar poprosić o porządniej niż ten, +1 niemniej :) – VoodooChild

+0

Twoje uczucie jest prawdziwe, ale jest to dobra odpowiedź tak. – ProfK

9

Nie sądzę, że używanie metody rozszerzenia jest złym pomysłem.

public static int NullableCount<T>(this IEnumerable<T> collection) 
{ 
    return collection == null ? 0 : collection.Count(); 
} 
+1

+1 Zrobiłem dokładnie to samo - nazwałem je "CountOrZero". Osobiście uważam, że jest jaśniejszy. –

2

Po prostu stwórz własną metodę rozszerzenia, która obsługuje wyliczenia zerowe, jak chcesz.

public int CountOrNull<T>(this IEnumerable<T> source) 
{ 
    return source == null ? 0 : source.Count(); 
} 

Następnie można po prostu użyć:

var list1 = new int[] { 1, 2, 3, 4 }; 
var list2 = (int[])null; 

var count1 = list1.CountOrNull(); // 4 
var count2 = list2.CountOrNull(); // 0 

to jest wielka rzecz o metodach przedłużenia. Nadal działają dobrze, nawet jeśli obiekt, na który się wydaje, że wywołuje tę metodę, to null.

+0

_ @ Noldorin: _ Naprawiono literówkę w twoim przykładzie kodu (komentarz '// 4'); może sprawdź, czy to rzeczywiście jest to, co zamierzałeś. – stakx

+0

@stakx: Dzięki; to był rzeczywiście literówka. – Noldorin

2

Chciałbym również napisać własną metodę rozszerzenia CountOrZeroForNull, jak pokazano w innych odpowiedziach.

Poza tym ... Zamiast:

var count = (myEnumerable ?? new string[0]).Count(); 
          // ^^^^^^^^^^^^^ 

można napisać:

var count = (myEnumerable ?? Enumerable.Empty<string>()).Count(); 
          // ^^^^^^^^^^^^^^^^^^^^^^^^^^ 

nie złagodzić swój konkretny problem, ale omija alokacji nieużywanym tablicy. (Enumerable.Empty<T> jest najprawdopodobniej realizowany jako prosty yield break oświadczeniu.)

+0

Obecna implementacja 'Enumerable.Empty ' faktycznie zwraca pojedynczą pustą tablicę 'T []'. – LukeH

+0

_ @ LukeH: _ Nie pomyślałbym o tym. Dzięki za to. – stakx

-2
var count = 0; 

if (myEnumerable != null) 
    count = myEnumerable.Count(); 

Chociaż to nie jest tak techniczny jak innych odpowiedzi, to zdecydowanie najbardziej czytelny.

+2

Nie sądzę, że te trzy linie są bardziej czytelne niż dobrze nazwana metoda rozszerzenia. – Lee

+0

Tak, chcę uniknąć wielokrotnego powtarzania tego samego sprawdzenia. W końcu to było moje pytanie. – ProfK

+1

Heh, może czytasz pytanie? –

1

Jakie działania podejmujesz, jeśli zwrócona wartość wynosi 0?

Jeśli to co ciekawe, może trzeba zastosować metodę IsNullOrEmpty przedłużacza HAACK za IEnumerable tak:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) 
{ 
    return items == null || !items.Any(); 
} 

Link jest http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx

Wysłany jako komentarz na blogu, można także znaleźć Exception klasa napisałem iść z tym:

public class ArgumentNullOrEmptyException : ArgumentNullException 
{ 
    public ArgumentNullOrEmptyException(string paramName) : base(paramName) 
    {} 

    public ArgumentNullOrEmptyException(string paramName, string message) : base(paramName, message) 
    {} 

    public override string Message 
    { 
     get 
     { 
      return "Value cannot be null nor empty.{0}Parameter name: {1}".FormatWith(Environment.NewLine, ParamName); 
     } 
    } 
} 
5

użyć niestandardowego extensi na metodzie:

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

... 

int count = myEnumerable.EmptyIfNull().Count(); 
+0

+1, myślę, że jest to najczystsze z wymienionych rozwiązań metod rozszerzeń. Jest bardzo jednoznaczne, że zakładasz, że wartość null jest przeliczalna na po prostu pustą, po czym możesz pracować z przeliczalnymi jak zwykle. –

Powiązane problemy