RCode

a software development blog by Bojan Resnik

Archive for June, 2009

C# lambda and foreach variable

Posted by Bojan Resnik on June 17, 2009

Can you guess what the output of the following program is?

using System;
using System.Collections.Generic;

namespace Lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            var strings = new[] {"a", "b", "c"};
            var actions = CreateActions(strings);
            actions.ForEach(f => f());
        }
        
        private static List<Action> CreateActions(IEnumerable<string> strings)
        {
            var actions = new List<Action>();
            
            foreach (var s in strings)
                actions.Add( () => Console.WriteLine(s) );
            
            return actions;
        }
    }
}

I expected to see all three strings (a, b and c), but instead I got this:
First output

While analyzing the IL code with Reflector I learned a thing or two about lambdas in C#.
When a lambda is encountered by the compiler, it generates a class which has a field for each local variable used by the lambda. In this case, the generated class would look like this in C#:

private sealed class <>c_DisplayClass3
{
    public string s;
    public void <Main>b_0()
    { Console.WriteLine(this.s); }
}

Of course, the above is not valid C# due to invalid characters in identifiers, but is pretty much what is produced in the IL.
So far so good – no real surprises here. However, look at this code which is my translation from IL to C# of the CreateActions method:

private static List<Action> CreateActions(IEnumerable<string> strings)
{
    List<Action> actions = new List<Action>();
    using (IEnumerator<string> enumerator = strings.GetEnumerator())
    {
        // Note 1: The lambda is created outside of the loop
        <>c_DisplayClass3 lambda = new <>c_DisplayClass3();

        string s;
        while (enumerator.MoveNext())
        {
            s = enumerator.Current;

            // Note 2: The instance field is reassigned each time
            lambda.s = s;
            actions.Add(lambda);
        }
    }
    return actions;
}

The reason for the strange output is clear now – the compiler did not create a lambda object in each iteration but rather reused the existing one each time. After the loop, all items in the actions list are actually the same instance and their s field is the last element of the collection. Apparently, C# compiler creates a lambda instance immediately before the local variable it uses. So, in order to force it to create a new lambda for each iteration, we need to introduce a new local variable in the loop:

private static List<Action> CreateActions(IEnumerable<string> strings)
{
    var actions = new List<Action>();
    
    foreach (var s in strings)
    {
        // This variable will be used in the lambda
        var lambda_param = s;
        actions.Add( () => Console.WriteLine(lambda_param) );
    }
    
    return actions;
}

With this modification the program now produces this output:
Second output

kick it on DotNetKicks.comShout it

Posted in .NET, C# | Tagged: , , | 33 Comments »

Chaos and Order on Disk

Posted by Bojan Resnik on June 2, 2009

Yesterday I was searching for a program on my external disk, yet again. I’ve been sick and tired of searching for stuff on it for a long time, and have been contemplating to reorganize it in order to make things more logical. A lot of stuff, both useful and not, has accumulated over the years, and, needless to say, many of them are in various, completely illogical places. There are tutorials and source codes dating back over a decade ago – mostly public domain, but there are some of my own as well. There are also utility programs that I just cannot be bothered to download each time I install a new machine, such as Winamp, Avira Antivirus, Opera, Python, and a multitude of others. Some of the stuff are backups (usually in forms of disk images) of software CDs and DVDs. And finally, there are numerous silly texts, pictures and the like.

At some point, up to about 5 years ago, I had a system, and the stuff was organized according to it.But, alas, some times I was in a hurry and just wanted to copy something over, and at other times I just couldn’t come up with a logical place for an item. And so, file by file, folder by folder, everything turned to chaos. Well, to be completely honest, it’s not that chaotic. It still has some leftover organization from my old system and I can (mostly) remember where things are. But, there are many things I would like to see categorized differently, in different folders, some packed with WinRAR, some unpacked.

It would be nice if I didn’t have to do all these by hand, so I started thinking about a program that could help me do most of these. Some of the requirements I can think of include:

  • Has to run off disk – no installation necessary
  • Minimal requirements (.NET framework is ok)
  • It must work with physical files and folders – no database or some such required.
    Basically, I’d like to run it and have it automatically collect everything on disk, allowing me to categorize the stuff without moving it around
  • Metadata must be kept with physical files/folders.
    If I move a folder manually, I want it to retain all the categories it belonged to
  • Easy searching by name, description, category

Apart from these basic requirements, I’d like it to also have some other things I find useful:

  • Automatically update installations
    For example, it should connect to Winamp site and download the latest installation if necessary
  • Automatically install programs
  • Launch viewers for images, PDF, HTML, etc.
  • Reorganize files and folders
  • Pack/unpack entire applications

An application that satisfies the basic requirements would be extremely useful to me, but I would ultimately want one that satisfies these additional requirements as well. I am seriously thinking of starting this application as an open source project, but I am currently overwhelmed with other issues. Still, I think I might start it in the near future.

Posted in Uncategorized | Tagged: , | Leave a Comment »