Pages

Saturday, February 20, 2010

C# ICollection Extensions

C# ICollection Extensions:

One thing I love about the C# (3.5) are lambda expressions and what can be done to them, they provide a very flexible method of writing more functional code, take linq for e.g.

The ICollection interface provides a handful of extensions for more functional way of writing code which I use regularly in C# (especially in data access services), but it has some features missing that you would wish to have.

We could add a MappingObject as an Extension to ICollection, but I'm not going to do that here, instead we are going to add another missing feature that comes in handy in Testing, generating items for a collection based on a lambda function.

So let's see the implementation:
    /// <summary>
    /// ICollection Extensions
    /// </summary>
    public static class ICollectionExtensions
    {
        /// <summary>
        /// Generates items based on a given function.
        /// </summary>
        /// <param name="collection">collection.</param>
        /// <param name="length">length.</param>
        /// <param name="func">func.</param>
        /// <returns>List of System Collections Generic I Collection T.</returns>
        public static ICollection<T> Generate<T>
            (this ICollection<T> collection, int length, Func<int, T> func) 
            where T : class
        {
            for (int i = 0; i < length; i++)
            {
                collection.Add(func(i));
            }

            return collection;
        }

        /// <summary>
        /// Generates the Unique items based on a given function and equality comparer.
        /// </summary>
        /// <param name="collection">collection.</param>
        /// <param name="length">length.</param>
        /// <param name="func">func.</param>
        /// <param name="comparer">comparer.</param>
        /// <returns>List of System Collections Generic I Collection T.</returns>
        public static ICollection<T> GenerateUnique<T>
            (this ICollection<T> collection, int length, Func<int, T> func, IEqualityComparer<T> comparer)
            where T : class
        {
            T item = null;
            bool addItem = true;
            List<T> list = collection.ToList();

            for (int i = 0; i < length; i++)
            {
                addItem = true;
                item = func(i);

                if (collection.Count == 0)
                {
                    collection.Add(item);
                }
                else
                {
                    list.Add(item);

                    for (int n = 0; n < list.Count; n++)
                    {
                        if (comparer.Equals(item, list[n]))
                        {
                            addItem = false;
                            break;
                        }
                    }

                    if (addItem)
                    {
                        collection.Add(item);
                    }
                }
            }

            return collection;
        }
    }

Not very much to explain here, we have two basic functions, the first is quite obvious, it add an item to a collection that's a result of our lambda function with index parameter and with T result.

The second one is a bit more complicated code vise but the logic behind it is simple, add only unique items to the collection, based on a lambda function that don't satisfy the IEqualityComparrer.

In case you don't know IEqualityComparrer has just two methods that you need to implement:

- Equals
- GetHashCode

By implementing the first you can tell what conditions need to be satisfied for two objects to be considered equal, the second one is to have an unique hash code for a object.

Having those extensions we can write code in a more functional way like so:
        public class A
        {
            public int i;
            public string s;
            public string s2;
        }

        public class Comparer : IEqualityComparer<A>
        {
            public bool Equals(A x, A y)
            {
                return x.i == y.i;
            }

            public int GetHashCode(A obj)
            {
                return obj.ToString().ToLower().GetHashCode();
            }
        }

        List<A> testFirst = (List<A>)new List<A>().Generate(20, x => new A() { i = 1 + x, s = "a" });
        List<A> testSecond = (List<A>)new List<A>().Generate(10, x => new A() { i = 1 + x });
        testSecond.GenerateUnique(20, x => new A() { i = 2 }, new Comparer());

I must say that I like this kind of code writing style, it may not be appealing to all, but overall I'm glad that I have this feature, it can be a real time saver in some cases.

No comments:

 
ranktrackr.net