uhlenheuerdotnet
programming, .NET, linux and others

F# - Compiling lambda expressions

by Gregor Uhlenheuer on June 7, 2012

If you try to compile a lambda expression in F# into an internal delegate type you should be warned because this won’t work as you would expect it from C# behavior for example.

In order to better illustrate what I mean here is a small example (which actually does not work):

module internal ReflectionHelpers =

    open System
    open System.Linq.Expressions
    open System.Reflection

    // this is the delegate type we want to use
    type GetterFunc<'T> = delegate of 'T -> obj

    let getGetter<'a> (p : PropertyInfo) =
        let inst = Expression.Parameter(p.DeclaringType, "i")
        let prop = Expression.Property(inst, p)
        let conv = Expression.Convert(prop, typeof<obj>)

        // this will throw an ArgumentNullException
        Expression.Lambda<GetterFunc<'a>>(conv, inst).Compile()

The above code snippet compiles just fine but on execution you will get an ArgumentNullException. The problem is somewhat hidden because the method Expression.Lambda tries to find a public Invoke method on the given delegate type. This works on C# as expected but in F# the Invoke method is defined with the same visibility as the declaring type (which is internal in this example).

As of now you only have to workarounds to choose from:

  1. Either use a public delegate type
  2. or use an internal delegate in C# code an reference it via InternalsVisibleTo

In contrast to that the following C# snippet works without any problems:

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace TestSnippets
{
    internal static class ReflectionHelpers
    {
        internal delegate object GetterFunc<T>(T element);

        internal static GetterFunc<T> GetGetterFunc<T>(PropertyInfo property)
        {
            var inst = Expression.Parameter(property.DeclaringType, "i");
            var prop = Expression.Property(inst, property);
            var conv = Expression.Convert(prop, typeof(object));

            return Expression.Lambda<GetterFunc<T>>(conv, inst).Compile();
        }
    }
}

This post is tagged with f#, .net, programming and reflection