Many times, even in .NET v2 with its lovely List<T>, you need to work with arrays. Many of those many times you will want to perform some common tasks such as checking if an element exists in the array or not. Unfortunately arrays do not have a Contains() method so you end up writing the same few lines of code over and over again until you decide you’ve had enough and you add a static method for it in your library.

 

In this particular case, with version 1 of the framework you would have two options. Either use the IEnumerable interface and loop through the array using a foreach statement or loop through the array using an index.

 

IEnumerable

 

    public static bool Contains(IEnumerable array, object value)

    {

        foreach (object obj in array)

        {

            if (obj.Equals(value))

            {

                return true;

            }

        }

 

        return false;

    }

 

Index

 

    public static bool Contains(Array array, object value)

    {

        for (int index = 0; index < array.Length; index++)

        {

            if (array.GetValue(index).Equals(value))

            {

                return true;

            }

        }

 

        return false;

    }

 

Both of these methods will work fine and continue to work fine in version 2 of the framework. As you have probably noticed though, there is no differentiation made between arrays that contain reference types and those that contain value types. In other words, performance is not optimal for when arrays containing value types are used. Here are a few numbers from when using these two ways of iterating over large arrays (average out of 3 times):

 

IEnumerable

 

Array of integers: 2921ms

Array of strings: 937ms

Array of objects: 863ms

 

Index

 

Array of integers: 2750ms

Array of strings: 816ms

Array of objects: 762ms

 

As expected using the index rather than the IEnumerable interface is quicker, but in both cases there is a performance hit when iterating through an array of integers.

 

We can overcome this issue with the help of Generics. Here is the code:

 

    public class ArrayHelper<T>

    {

        private ArrayHelper()

        {

        }

 

        public static bool Contains(T[] array, T value)

        {

            for (int index = 0; index < array.Length; index++)

            {

                if (Singleton.Comparer.Equals(array[index], value))

                {

                    return true;

                }

            }

 

            return false;

        }

 

        private class Singleton

        {

            public static readonly EqualityComparer<T> Comparer = EqualityComparer<T>.Default;

        }

    }

 

The Contains method takes an array of type T, which we still don’t know if it is a reference or a value type. Since it performs better we use the index to go through the array, just like before, only now the comparison is handled by an instance of EqualityComparer<T>. What the Default property does is explained nicely by the documentation

 

The Default property checks whether type T implements the System.IEquatable generic interface and if so returns an EqualityComparer that uses that implementation. Otherwise it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.

 

This allows for the comparison of value types without boxing them. Let’s have a look at how this solution performs running the same test:

 

Array of integers: 97ms

Array of strings: 388ms

Array of objects: 327ms

 

Ahhh, that’s better. The reason for the class Singleton is simply thread-safe lazy initialization and is not really required if the class ArrayHelper is only going to have the Contains method, but I am sure a few more methods will make their way in there in the future.