Replacing the for loop, using extensions

ddanbe 0 Tallied Votes 381 Views Share

I'm a great fan of extensions in C#. See also this previous snippet.
Extensions are really simple to use. Start with adding a static class containing static methods.
Note the special use of the keyword this in the Times extension method.
The next code snip is how you could use this extension, eliminating the use of the for.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExtensionSpace // use a special namespace for extensions
{
    public static class IntExtensions //extensions for the integer type
    {
        /// <summary>
        /// Repeat an action until EndCount
        /// Counting starts at zero, EndCount not included
        /// </summary>
        /// <param name="EndCount"></param>
        /// <param name="action takes one int and returns void"></param>
        public static void Times(this int EndCount, Action<int> action)
        {
            for (int i = 0; i < EndCount; i++)
            {
                action(i);
            }
        }

        //more extension methods . . .
    }
}

-----------------------------------------------------------------------------------

sing System;
using System.Collections.Generic;
using ExtensionSpace; // notice! 

namespace Extensiontest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Write the square of the numbers 0 to 9 to the console
            10.Times(n => DoTheSquare(n));

            Console.WriteLine("=====================");

            // Equivalent for loop
            for (int i = 0; i < 10; i++)
            {
                DoTheSquare(i);
            }

            Console.ReadKey();
        }

        static void DoTheSquare(int n)
        {
            Console.WriteLine("The square of {0} is {1}", n, n * n);
        }

    }
}
Mike Askew 131 Veteran Poster Featured Poster

I like it!

But from a readability perspective in my opinion the for-loop is better. Can't skim read over the given extension example and know what it does too easily.

ddanbe 2,724 Professional Procrastinator Featured Poster

Of course the for loop still has its merits!
Your remark is correct. With this extension it isn't very obvious that a counter is incremented, like it is clearly visible, when using a for.
I'm in fact not going to use it very much myself I guess and stick with a for loop.
But still, I find it truly astonishing that a mere integer litteral can be used like an object.

Ketsuekiame 860 Master Poster Featured Poster

Actually we use a similar construct here; it's great for doing something X times but be warned that there are three levels of indirection and a delegate object construction plus the delegate invocation.
It has an impact when you get into large numbers.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Hmm, I'm not sure I see the benefit in this case. Though variations on ForEach are relatively common. As an example, I have an extension method for ForEach over an IEnumerable<> and another that reports progress over iteration:

/// <summary>
/// Performs an action on each item in an enumerable collection.
/// </summary>
/// <typeparam name="T">The type of items in the collection.</typeparam>
/// <param name="action">The action to perform.</param>
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    foreach (var item in items)
    {
        action(item);
    }
}

/// <summary>
/// Performs an action on each item in an enumerable collection with a progress indicator.
/// </summary>
/// <typeparam name="T">The type of items in the collection.</typeparam>
/// <param name="action">The action to perform.</param>
/// <param name="startPercent">Starting progress percentage.</param>
/// <param name="finishPercent">Progress percentage after all items have been traversed.</param>
/// <remarks>
/// The progress percentage is passed to the action for use by the caller.
/// </remarks>
public static void ForEach<T>(this IEnumerable<T> items, Action<T, double> action, double startPercent = 0, double finishPercent = 100)
{
    double progress = startPercent;
    double progressRange = finishPercent - startPercent;
    double progressDelta = progressRange / items.Count();

    foreach (var item in items)
    {
        action(item, progress);
        progress += progressDelta;
    }
}

Replacing a for loop though? I can see it to a certain extent if you want to encourage a more functional style of coding, but use of for should be relatively rare these days anyway. Further, Linq already has Enumerable.Range which somewhat intersects with your extension method's purpose.

ddanbe commented: Thanks for sharing. +15
Ketsuekiame 860 Master Poster Featured Poster

There is no functional benefit, you are correct. But it does mean that some things compress down nicely so instead of being 5 lines they're only 1. That's pretty much it.

Also watch out @deceptikon, there is already a ForEach method on List<T> I don't know what the interaction would be here.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Also watch out @deceptikon, there is already a ForEach method on List<T>

Yup, and only List<>, which is why the extension method is beneficial. ;)

I don't know what the interaction would be here.

In method overload resolution, more specific ownership takes precedence. So any locally defined method throughout the inheritance hierarchy will be preferred over an extension method. In this case, when both List<> and the IEnumerable<> extension method are in scope, List<>.ForEach will always be selected for a List<> object.

kplcjl 17 Junior Poster

Note that the name "Times" does not mean multiplication is being done, it means the routine defined is being repeated in a Linq expression, so maybe a better name may be called for. I can't think of a better name myself...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.