Click here to Skip to main content
15,887,746 members
Articles / Programming Languages / C#

IsNullOrEmpty for Generic Collections in C#

,
Rate me:
Please Sign up or sign in to vote.
3.43/5 (18 votes)
12 Aug 2015CPOL 33.6K   11   22
IsNullOrEmpty for Generic Collections in C#

In this code snippet, we will see the creation and implementation of IsNullOrEmpty for collections.

Can I Implement IsNullOrEmpty for my Generic Collections/Lists?

It's out of C#. Unfortunately, there is only one method which is of a String method String.IsNullOrEmpty() available, framework does not provide us such things.

What is the Solution for this?

A solution is only an Extension Method, we just need to create an Extension Method which will provide the same facility: Here is the extension method:

C#
public static class CollectioncExtensionMethods  
    {  
        public static bool IsNullOrEmpty<T>(this IEnumerable<T> genericEnumerable)  
        {  
            return ((genericEnumerable == null) || (!genericEnumerable.Any()));  
        }  
  
        public static bool IsNullOrEmpty<T>(this ICollection<T> genericCollection)  
        {  
            if (genericCollection == null)  
            {  
                return true;  
            }  
            return genericCollection.Count < 1;  
        }  
    }

Enjoy the benefit of these extension methods. :)

C#
var serverDataList = new List<ServerData>();  

//It will use IsNullOrEmpty<T>(this ICollection<T> gnericCollection)
var result = serverDataList.IsNullOrEmpty();  
 
var serverData = new ServerDataRepository().GetAll();
              
// It will use IsNullOrEmpty<T>(this IEnumerable<T> genericEnumerable)  
var result = serverData.IsNullOrEmpty();

Can You Think What It Will Give When I Call serverDataList.Count and When I Call serverData.Count?

Hint: One will give me O(n) while other O(1), enjoy! :)

If still confused, view this video on .NET collection by legend author, Mr. Shivprasad Koirala.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer
India India
Learning never ends.

Written By
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
D V L23-Aug-15 19:55
professionalD V L23-Aug-15 19:55 
AnswerRe: My vote of 5 Pin
Gaurav Aroraa23-Aug-15 21:56
professionalGaurav Aroraa23-Aug-15 21:56 
QuestionNot really a good idea Pin
William E. Kempf13-Aug-15 6:01
William E. Kempf13-Aug-15 6:01 
AnswerRe: Not really a good idea Pin
mtiede13-Aug-15 10:50
mtiede13-Aug-15 10:50 
GeneralRe: Not really a good idea Pin
codefabricator18-Aug-15 5:55
codefabricator18-Aug-15 5:55 
QuestionNice trick Pin
DotNetForAll13-Aug-15 3:57
DotNetForAll13-Aug-15 3:57 
AnswerRe: Nice trick Pin
Gaurav Aroraa13-Aug-15 4:00
professionalGaurav Aroraa13-Aug-15 4:00 
QuestionGreat Pin
irneb13-Aug-15 2:13
irneb13-Aug-15 2:13 
AnswerRe: Great Pin
Gaurav Aroraa13-Aug-15 3:53
professionalGaurav Aroraa13-Aug-15 3:53 
GeneralRe: Great Pin
irneb13-Aug-15 19:59
irneb13-Aug-15 19:59 
I've done a bit of testing, and yes the Count is a slight bit faster (around 67% of the time taken by Any). But a more beneficial alternative is Array Length - around 28% of the time taken by Any.

However:Something very-very strange. I've tried a benchmark of this on two systems, but get extreme disparity. E.g.
C#
namespace EmptyOrNullTest
{
    class Program
    {
        const long REPEAT = 0x3FFFFFF;
        const int SIZE = 20;

        static void Print(StreamWriter f, string name, long repeat, TimeSpan time)
        {
            var s = string.Format("{0}\t{1}\t{2}", name, REPEAT, Test(YieldIntAny, REPEAT));
            f.WriteLine(s);
            Console.WriteLine(s);
        }

        static void Main(string[] args)
        {
            using (StreamWriter f = new StreamWriter(@"Results.CSV", false, Encoding.UTF8)) {
                Print(f, "YieldIntAny", REPEAT, Test(YieldIntAny, REPEAT));
                Print(f, "EnumIntAny", REPEAT, Test(EnumIntAny, REPEAT));
                Print(f, "EnumIntNullAny", REPEAT, Test (EnumIntNullAny, REPEAT));
                Print(f, "ArrayIntAny", REPEAT, Test (ArrayIntAny, REPEAT));
                Print(f, "ArrayIntLength", REPEAT, Test (ArrayIntLength, REPEAT));
                Print(f, "ArrayIntNullAny", REPEAT, Test (ArrayIntNullAny, REPEAT));
                Print(f, "ArrayIntNullLength", REPEAT, Test (ArrayIntNullLength, REPEAT));
                Print(f, "ColIntAny", REPEAT, Test (ColIntAny, REPEAT));
                Print(f, "ColIntCount", REPEAT, Test (ColIntCount, REPEAT));
                Print(f, "ColIntNullCount", REPEAT, Test (ColIntNullCount, REPEAT));
                Print(f, "ColIntNullAny", REPEAT, Test (ColIntNullAny, REPEAT));
                Print(f, "EnumEx", REPEAT, Test (EnumEx, REPEAT));
                Print(f, "ArrayEx", REPEAT, Test (ArrayEx, REPEAT));
                Print(f, "ArEnEx", REPEAT, Test (ArEnEx, REPEAT));
                Print(f, "ColEx", REPEAT, Test (ColEx, REPEAT));
                Print(f, "ColEnEx", REPEAT, Test (ColEnEx, REPEAT));
            }
            Console.ReadLine ();
        }

        #region Helpers

        void TestArrayLength ()
        {

        }

        static TimeSpan Test(Action act, long repeat = 1)
        {
            if (repeat < 1) {
                throw new ArgumentOutOfRangeException ("repeat", "must be a positive integer");
            }

            Stopwatch sw = new Stopwatch ();
            act ();
            act ();
            System.GC.Collect ();
            System.GC.WaitForPendingFinalizers ();
            sw.Restart ();
            for (long i = 0; i < repeat; i++) {
                act ();
            }
            sw.Stop ();
            return sw.Elapsed;
        }

        static Program()
        {
            ArrayInt = new int[SIZE];
            ColInt = new List<int>();
            for (int i = 0; i < SIZE; i++) {
                ArrayInt[i] = i;
                ColInt.Add(i);
            }
            EnumInt = ColInt;
        }

        static IEnumerable<int> YieldInt
        {
            get
            {
                for (int i = 0; i < SIZE; i++)
                {
                    yield return i;
                }
            }
        }
        static IEnumerable<int> EnumIntNull = null;
        static IEnumerable<int> EnumInt;

        static int[] ArrayInt;
        static int[] ArrayIntNull = null;

        static ICollection<int> ColInt;
        static ICollection<int> ColIntNull = null;

        static bool TestEnumAny<T> (IEnumerable<T> en)
        {
            return (en == null) || !en.Any ();
        }

        static bool TestArrayLength<T> (T[] ar)
        {
            return (ar == null) || (ar.Length < 1);
        }

        static bool TestCollection<T> (ICollection<T> col)
        {
            return (col == null) || (col.Count < 1);
        }

        #endregion

        static void YieldIntAny ()
        {
            bool b = TestEnumAny (YieldInt);
        }
        static void EnumIntAny ()
        {
            bool b = TestEnumAny (EnumInt);
        }
        static void EnumIntNullAny ()
        {
            bool b = TestEnumAny (EnumIntNull);
        }
        static void ArrayIntAny ()
        {
            bool b = TestEnumAny (ArrayInt);
        }
        static void ArrayIntNullAny ()
        {
            bool b = TestEnumAny (ArrayIntNull);
        }
        static void ArrayIntLength ()
        {
            bool b = TestArrayLength (ArrayInt);
        }
        static void ArrayIntNullLength ()
        {
            bool b = TestArrayLength (ArrayIntNull);
        }
        static void ColIntAny ()
        {
            bool b = TestCollection (ColInt);
        }
        static void ColIntNullAny ()
        {
            bool b = TestCollection (ColIntNull);
        }
        static void ColIntCount ()
        {
            bool b = TestCollection (ColInt);
        }
        static void ColIntNullCount ()
        {
            bool b = TestCollection (ColIntNull);
        }
        static void EnumEx ()
        {
            bool b = EnumInt.IsNullOrEmpty ();
        }
        static void ArrayEx ()
        {
            bool b = ArrayInt.IsNullOrEmpty ();;
        }
        static void ArEnEx ()
        {
            bool b = ((IEnumerable<int>)ArrayInt).IsNullOrEmpty ();;
        }
        static void ColEx ()
        {
            bool b = ColInt.IsNullOrEmpty ();
        }
        static void ColEnEx ()
        {
            bool b = ((IEnumerable<int>)ColInt).IsNullOrEmpty ();
        }
    }
}

And the extension methods I used in above:
C#
public static class XEmptyOrNullEnumerables
{
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> self)
    {
        return (self == null) || !self.Any();
    }

    public static bool IsNullOrEmpty<T>(this T[] self)
    {
        return (self == null) || (self.Length < 1);
    }

    public static bool IsNullOrEmpty<T>(this ICollection<T> self)
    {
        return (self == null) || (self.Count < 1);
    }
}

All this compiled to Release build using AnyCPU and then run from a console to avoid any IDE interference.

System 1:
MonoDev 5.5 on Kubuntu 14.04 (64bit), i7-2600 with 16GB RAM.
FunctionName   Iterations  Seconds
YieldIntAny 67108863    2.33333333333333
EnumIntAny  67108863    0.77893518518519
EnumIntNullAny  67108863    0.30902777777778
ArrayIntAny 67108863    0.84143518518519
ArrayIntLength  67108863    0.24537037037037
ArrayIntNullAny     67108863    0.32754629629630
ArrayIntNullLength  67108863    0.24537037037037
ColIntAny       67108863    0.51273148148148
ColIntCount     67108863    0.51620370370370
ColIntNullCount     67108863    0.31597222222222
ColIntNullAny       67108863    0.31597222222222
EnumEx          67108863    0.78703703703704
ArrayEx         67108863    0.25347222222222
ArEnEx          67108863    0.87731481481482
ColEx           67108863    0.55092592592593
ColEnEx         67108863    0.82175925925926

...
BUT
...

System 2:
VisualStudio 2013 Community Edition, Win8.1 Pro 64 bit, i7-5930K, 64GB RAM. DotNet frameworks 2.0, 3.0, 3.5, 4.0 & 4.5.1 installed.
FunctionName   Iterations  Seconds
YieldIntAny 67108863    1.62037037037037
EnumIntAny  67108863    1.94097222222222
EnumIntNullAny  67108863    1.94097222222222
ArrayIntAny 67108863    1.94212962962963
ArrayIntLength  67108863    1.94328703703704
ArrayIntNullAny 67108863    1.94212962962963
ArrayIntNullLength  67108863    1.94328703703704
ColIntAny   67108863    1.96412037037037
ColIntCount 67108863    1.94791666666667
ColIntNullCount 67108863    1.94791666666667
ColIntNullAny   67108863    1.93981481481482
EnumEx  67108863    1.94212962962963
ArrayEx 67108863    1.94212962962963
ArEnEx  67108863    1.94097222222222
ColEx   67108863    1.94444444444444
ColEnEx 67108863    1.94097222222222

It's as if something else is taking up so much time in the VS compiled variant that the test is meaningless.
GeneralRe: Great Pin
Gaurav Aroraa13-Aug-15 20:11
professionalGaurav Aroraa13-Aug-15 20:11 
GeneralRe: Great Pin
irneb14-Aug-15 22:55
irneb14-Aug-15 22:55 
AnswerRe: Great Pin
Gaurav Aroraa15-Aug-15 22:49
professionalGaurav Aroraa15-Aug-15 22:49 
GeneralRe: Great Pin
irneb16-Aug-15 23:46
irneb16-Aug-15 23:46 
AnswerRe: Great Pin
Gaurav Aroraa17-Aug-15 1:18
professionalGaurav Aroraa17-Aug-15 1:18 
GeneralRe: Great Pin
irneb17-Aug-15 4:48
irneb17-Aug-15 4:48 
AnswerRe: Great Pin
Gaurav Aroraa17-Aug-15 22:37
professionalGaurav Aroraa17-Aug-15 22:37 
GeneralRe: Great Pin
Gaurav Aroraa24-Aug-15 5:29
professionalGaurav Aroraa24-Aug-15 5:29 
GeneralMy vote 5 Pin
Shuby Arora12-Aug-15 10:56
Shuby Arora12-Aug-15 10:56 
GeneralRe: My vote 5 Pin
Gaurav Aroraa13-Aug-15 3:53
professionalGaurav Aroraa13-Aug-15 3:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.