Part 2 : Digging Deeper into Lambadas, Extension Methods, and Linq

The world’s most common extension method and an attempt at a definitive version.

In this post I’ll be digging deeper into doing things I’ve always wanted to have in .NET yet didn’t. For example, I know I am not alone in wanting an IList (be it an IList<T> or a simple non-generic IList) to provide me a .foreach method as you get in a List<T>). This is just one of many things we address here (and more).

From the concrete to the abstract

I was having problems with entries in my path environmental variable, and I wanted an easy way to flag bad entries and also allow me to move the entries in the list up or down easily. This was made apparent by my use of a tool called ‘Dependency Walker’. It’s hard to live without but that’s another post. See the screen shot below:

Image-0001

Click here to go to ‘Dependency Walker’

Test to Code

 

    /// <summary>
    /// Unit Test to Validate that the logic related to     /// 'show combined extensions using paths' is functioning
    /// </summary>
    /// Documentation Created 5/22/2008
    [Test]
    public void shouldShowCombinedExtensionsUsingPaths()
    {
        var _directoriesInPath = EnvironmentVariableTarget.             Process.GetParsedValues("PATH");

        Assert.That(_directoriesInPath, Is.                TypeOf(typeof(String[])));
        Assert.IsTrue(!_directoriesInPath.IsNullOrEmpty());

        _directoriesInPath.ForEach(
            x =>
            {
                if (!Directory.Exists(x))
                    Console.WriteLine("MIssing Directory! " + x);
            });
    }

Above is the test (that also works). Before I launch into why this is interesting, what looks different?

1) EnvironmentVariableTarget : This is Microsoft’s type not mine. It’s the enum used to specify the target search on the environmentals.

2) _directoriesInPath : This is a string[] as you can see from the Assertion. But how does it support ForEach?

3) GetParsedValues() : What is that exactly?

*** As this is so common I decided to try to craft a definitive version of ForEach that would work across non-generic collections, generic collection, and specific type specification on the targeted items in the collection for generics .  ***

In order to enable ForEach behavior I needed to this code which is by far the most common extension method in all the C# 3.0 code alive today.

 

    /// <summary>
    /// Requires generic IEnumerable and is most common now
    /// </summary>
    /// <typeparam name="TContainedType">The type of the contained type.</typeparam>
    /// <param name="baseEnum">The base enum.</param>
    /// <param name="actionPerform">The action perform.</param>
    /// <returns></returns>
    /// Documentation Created 7/20/2008
    public static IEnumerable<TContainedType> ForEach<TContainedType>(
           this IEnumerable<TContainedType> baseEnum,
               Action<TContainedType> actionPerform) {

        return ForEachInner(baseEnum, actionPerform);
    }

    /// <summary>
    /// The most explicit case
    /// </summary>
    /// <typeparam name="TBase">The type of the base.</typeparam>
    /// <typeparam name="TContainedType">The type of the contained type.</typeparam>
    /// <param name="baselineEnumerable">The baseline enumerable.</param>
    /// <param name="actionPerform">The action perform.</param>
    /// <returns></returns>
    /// Documentation Created 7/20/2008
    public static IEnumerable<TContainedType> ForEach<TBase, TContainedType>(
              this TBase baselineEnumerable, Action<TContainedType> actionPerform)
                   where TBase : IEnumerable {

        return ForEachInner(baselineEnumerable.OfType<TContainedType>(), actionPerform);
    }

    /// <summary>
    /// The least restrictive case
    /// </summary>
    /// <param name="baseEnum">The base enum.</param>
    /// <param name="actionPerform">The action perform.</param>
    /// <returns></returns>
    /// Documentation Created 7/20/2008
    public static IEnumerable<Object> ForEach(this IEnumerable baseEnum,                Action<Object>  actionPerform) {

        return ForEachInner(baseEnum.OfType<Object>(), actionPerform);
    }

    /// <summary>
    /// Do the actual work
    /// </summary>
    /// <typeparam name="TContainedType">The type of the contained type.</typeparam>
    /// <param name="baseEnum">The base enum.</param>
    /// <param name="actionPerform">The action perform.</param>
    /// <returns></returns>
    /// Documentation Created 7/20/2008
    private static IEnumerable<TContainedType> ForEachInner<TContainedType>(
        IEnumerable<TContainedType> baseEnum,
                       Action<TContainedType> actionPerform) {

        var getEnumerate = baseEnum.ToList();
        getEnumerate.ForEach(actionPerform);

        return getEnumerate;
    }

 

 

Notice that anything which implements IEnumerable is caught above, regardless of what the collection.

 

Digg This


Post a Comment