RCode

a software development blog by Bojan Resnik

Posts Tagged ‘.NET’

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

Advertisements

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

Passing C++/CLI delegate to native code

Posted by Bojan Resnik on May 18, 2009

Recently I had to interface a C++/CLI assembly with a native DLL written in C. This is mostly straightforward, but the C DLL could raise an internal event and provided a way to have the application notified of this event. In order to be informed, the application has to register a callback function that will be invoked by the DLL when the event is raised. The registration function is declared like this:

typedef void (__stdcall* EventCallback)();
void RegisterCallback(EventCallback callback);

Using an ordinary function for the callback would be easy, but I wanted to use a .NET delegate so that I could convert the native event into a .NET event. This scenario also turns out to be supported by .NET. All you need to take care of is to prevent the delegate from being moved or collected by the garbage collector.

public delegate void EventDelegate();

ref class NativeInterface
{
public:
    NativeInterface()
    {
        // Create the delegate from a member function
        nativeCallback_ = gcnew EventDelegate(this, &NativeInterface::Callback);

        // As long as this handle is alive, the GC will not move or collect the delegate
        // This is important, because moving or collecting invalidate the pointer
        // that is passed to the native function below
        delegateHandle_ = GCHandle::Alloc(nativeCallback_);

        // This line will actually get the pointer that can be passed to
        // native code
        IntPtr ptr = Marshal::GetFunctionPointerForDelegate(nativeCallback_);

        // Convert the pointer to the type required by the native code
        RegisterCallback( static_cast<EventCallback>(ptr.ToPointer()) );
    }

    !NativeInterface()
    {
        // Free the handle to the delegate, allowing GC to collect
        // the delegate
        if (delegateHandle_.IsAllocated)
            delegateHandle_.Free();
    }

private:
    GCHandle delegateHandle_;
    EventDelegate^ nativeCallback_;

    void Callback()
    {
        Console::WriteLine("Native event raised");
    }
};

kick it on DotNetKicks.comShout it

Posted in .NET, C++/CLI | Tagged: , , | 9 Comments »