Before I noticed how many other people had blogged about this same thing, I wrote an implementation of a "times" (integer extension) method -- the kind you'd find when coding in Ruby that is passed a block of code that it executes (n) times.
Consider the following (in Ruby):
#####################################
# prints:
# Ruby was here
# Ruby was here
2.times {
printf("Ruby was here\n")
}
#####################################
# prints:
# Ruby was here 0
# Ruby was here 1
2.times {|i|
printf("Ruby was here %d\n", i)
}
The closest to this I got in C# was:
public static void DoTest1()
{
/******************************************************\
* This technique is the actual goal of this exercise
\******************************************************/
2.times(DoWriteLine); // <-GOAL!
2.times(DoWriteLineAndNum);
// or
2.times(i => Console.WriteLine("CSharp was here"));
2.times(i => Console.WriteLine("CSharp was here: " + i));
}
The C# class I created (with two extension methods) looks like this:
using System;
using System.Linq;
namespace RubyLike
{
public static class CRubyLike
{
/// <summary>
/// Performs an action i number of times
/// </summary>
/// <param name="i">number of times to repeat</param>
/// <param name="action">action to be repeated</param>
public static void times(this int i, Action action)
{
Enumerable.Range(0, i).ToList().ForEach(n => action());
}
/// <summary>
/// Performs an action i number of times passing the
/// repeat target as a parameter.
/// Allowing: 5.times(n => Console.Write("hey"));
/// </summary>
/// <param name="i">number of times to repeat</param>
/// <param name="action">action to be repeated</param>
public static void times(this int i, Action<int> action)
{
int iCount=0;
Enumerable.Range(0, i).ToList().ForEach(n => action(iCount++));
}
}
}
Here is the C++ Example
// TestRubyLike_CPP.h
#pragma once
using namespace System;
using namespace RubyLike;
namespace TestRubyLike_CPP {
public ref class CTestRubyLike_CPP
{
private:
static void DoWriteLine(void)
{Console::WriteLine("C++ was here");}
static void DoWriteLine(int i)
{Console::WriteLine("C++ was here "+ i.ToString());}
public:
static void DoTest(void)
{
CRubyLike::times(2, gcnew Action(DoWriteLine));
CRubyLike::times(2, gcnew Action<int>(DoWriteLine));
CRubyLike::times(2, gcnew Action(Console::WriteLine));//blank/blank
CRubyLike::times(2, gcnew Action<int>(Console::WriteLine));//0/1
}
};
}
Here is the VB Example:
Imports System
Imports RubyLike
Public Class CTestRubyLike_VB
Private Shared Sub DoWriteLine()
Console.WriteLine("VB was here")
End Sub
Private Shared Sub DoWriteLine(ByVal i As Integer)
Console.WriteLine("VB was here: " & i)
End Sub
Public Shared Sub DoTest1()
Dim iVal As Integer = 2
iVal.times(New Action(AddressOf DoWriteLine))
iVal.times(New Action(Of Integer)(AddressOf DoWriteLine))
iVal.times(New Action(AddressOf Console.WriteLine)) 'blank/blank
iVal.times(New Action(Of Integer)(AddressOf Console.WriteLine)) '2/2
End Sub
Public Shared Sub DoTest2()
CRubyLike.times(2, New Action(AddressOf DoWriteLine))
CRubyLike.times(2, New Action(Of Integer)(AddressOf DoWriteLine))
CRubyLike.times(2, New Action(AddressOf Console.WriteLine)) 'blank/blank
CRubyLike.times(2, New Action(Of Integer)(AddressOf Console.WriteLine)) '2/2
End Sub
End Class
Here is the C# Example:
using System;
using RubyLike;
namespace TestRubyLike_CS
{
public static class CTestRubyLike_CS
{
private static void DoWriteLine()
{
Console.WriteLine("CSharp was here");
}
private static void DoWriteLineAndNum(int i)
{
Console.WriteLine("CSharp was here: " + i);
}
public static void DoTest1()
{
/******************************************************\
* This technique is the actual goal of this exercise
\******************************************************/
2.times(DoWriteLine); // <-GOAL!
2.times(DoWriteLineAndNum);
// or
2.times(i => Console.WriteLine("CSharp was here"));
2.times(i => Console.WriteLine("CSharp was here: " + i));
}
public static void DoTest2()
{
CRubyLike.times(2, DoWriteLine);
CRubyLike.times(2, DoWriteLineAndNum);
CRubyLike.times(2, (Action)Console.WriteLine);//blank/blank
CRubyLike.times(2, (Action<int>)Console.WriteLine);//2/2
}
}
}
Here is a calling program for these (in C#)
using System;
using TestRubyLike_CS;
using TestRubyLike_CPP;
using TestRubyLike_VB;
namespace TestRubyLike
{
public static class CTestRubyLike
{
static void Main(string[] args)
{
///////////////////////////////
// Make calls on extension methods
Console.WriteLine("C# Example 1: ---------------------");
CTestRubyLike_CS.DoTest1();
// or
///////////////////////////////////
// Make calls on static methods
Console.WriteLine("C# Example 2: ---------------------");
CTestRubyLike_CS.DoTest2();
///////////////////////
// Make calls from C++
Console.WriteLine("C++ Example: ----------------------");
CTestRubyLike_CPP.DoTest();
/////////////////////
// Make calls from VB
Console.WriteLine("VB Example 1: ---------------------");
CTestRubyLike_VB.DoTest1();
//or
Console.WriteLine("VB Example 2: ---------------------");
CTestRubyLike_VB.DoTest2();
}
}
}
And, of course, the output:
