Rubyish collections in C# 2.0

In the limited amount of time that I have played around with Ruby, I have been impressed with how easy it makes a lot of things. Utilizing the power of blocks, it is this simple to print out the contents of an array.

    list.each {|item| puts item}

C# 2.0 gives you something similar to blocks with the new anonymous methods. Say you want to show a message when a button is clicked. Before 2.0 you had to do quite a bit of coding to implement the feature.

First, you have to implement your method.

    private void button1_click(object sender, EventArgs e)
    {
        MessageBox.ShowMessage("Hello, World!");
    }

Then you have to assign the method to the click event.

   button1.Click +=  new System.EventHandler(button1_click);

With anonymous methods, this task becomes much simpler.

    button1.Click += delegate { MessageBox.Show("Hello, World!"); };

Granted, if you had a decent designer, most of this would be done automatically, but you can still see how much easier stuff like this is in C# 2.0.

After looking at the examples for anonymous methods, it got me thinking about whether you could implement methods on a list class similar to the way Ruby does. So I started by making a delegate method, and a descendent of ArrayList.

    delegate void EachDelegate(Object item);

    class MyCoolList: ArrayList
    {
        public void Each(EachDelegate delegateMethod)
        {
            foreach (object obj in this)
                delegateMethod(obj);
        }
    }

Now, to print out the contents to the command line.

    MyCoolList list = new MyCoolList();
    list.Add("foo");
    list.Add("bar");
    list.Add("baz");
    list.Each((EachDelegate)delegate(object obj) { Console.WriteLine(obj.ToString()); });

The syntax is a little ugly, but at least all of the code is there in the same method. Now that I have a class that implements each, lets look at leveraging generics to make the class, well more generic.

First we need to make our delegate generic.

    public delegate void EachDelegate<ReallyCoolListElement>(ReallyCoolListElement element);

Then we make our list class descend from List<T> and use the new generic delegate in our Each method.

    class MyReallyCoolList<ReallyCoolListElement> : List<ReallyCoolListElement>
    {
        public void Each(EachDelegate<ReallyCoolListElement> delegateMethod)
        {
            foreach (ReallyCoolListElement obj in this)
                delegateMethod(obj);
        }
    }

To use this new class we can modify the original code to look like this.

    MyRealyCoolList<string> list = new MyReallyCoolList<string>();
    list.Add("foo");
    list.Add("bar");
    list.Add("baz");
    list.Each((EachDelegate<string>)delegate(string element) { Console.WriteLine(element); });

Or if you wanted to use it to sum up a list of ints.

    int sum = 0;
    MyRealyCoolList<int> list = new MyReallyCoolList<int>();
    list.Add(1);
    list.Add(2);
    list.Add(3);
    list.Each((EachDelegate<int>)delegate(int element) { sum += element; });

The syntax in C# is not nearly as nice and sugary as Ruby, but this does demonstrate some of the cool new features that are being added to C# 2.0.

4 Responses to “Rubyish collections in C# 2.0”

  1. James Manning Says:

    Just a couple notes, trying to help out :)

    You don’t need to define EachDelegate, it already exists via the Action delegate: http://msdn2.microsoft.com/en-us/library/018hxwa8

    You don’t need to add a Each method when you subclass List, it already has the ForEach method that takes the Action delegate: http://msdn2.microsoft.com/en-us/library/bwabdf9z(en-US,VS.80).aspx

    The Action and Predicate (http://msdn2.microsoft.com/en-us/library/bfcke1bz) delegates are the ones I use the most.

    Also, the System.Array class has a lot of new generic methods so you can do the same kinds of operations on regular arrays as well: http://msdn2.microsoft.com/en-us/library/e23tz9hz(en-us,VS.80).aspx

  2. Brian Says:

    Guess I should have done a little more research before posting. Looks like Microsoft had some of the same great ideas and built them into the .NET 2.0 collections.

  3. Joe White Says:

    Actually, you wrote more Ruby code than you needed to print out a list… all you need is:

    puts list

  4. play slot bingo Says:

    play online slot slots slot play

Leave a Reply