by June 7, 2012
onIf 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:
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();
}
}
}