kongo2002
kongo2002

Reputation: 1024

Compile lambda expression with internal delegate type

I am having some trouble with compiling a lambda expression for a property getter in F# if the delegate type is internal. This is what the function looks like:

// if I omit the 'internal' here everything works as expected
module internal ReflectionHelpers =

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

    // it makes no difference if this delegate type is defined outside
    // of the module and marked as 'internal'
    type GetterFunc<'T> = delegate of 'T -> obj

    /// Build a getter expression function for the
    /// specified PropertyInfo
    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>)
        Expression.Lambda<GetterFunc<'a>>(conv, inst).Compile()

If I call this method with a public class I get an exception like this one (only if the ReflectionHelpers module is defined as 'internal'):

System.ArgumentNullException was unhandled by user code
  Message=Value cannot be null.
Parameter name: key
  Source=mscorlib
  ParamName=key
  StackTrace:
       at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
       at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
       at System.Dynamic.Utils.CacheDict`2.TryGetValue(TKey key, TValue& value)
       at System.Dynamic.Utils.TypeExtensions.GetParametersCached(MethodBase method)
       at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters)
       at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
       at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 parameters)
       at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, ParameterExpression[] parameters)
       ...

Probably I am missing an important point here but currently I cannot see any reason why this is happening.

Upvotes: 4

Views: 650

Answers (1)

desco
desco

Reputation: 16782

F# and C# use different strategies for emitting Invoke method for delegates. If you try to define similar delegate in C# it - delegate type will be internal but with public Invoke method. F# defines Invoke method with the same visibility as the declaring type. When code in Expression.Lambda tries to find Invoke method in given delegate type it looks only for public methods assuming that all compilers behave similar to C#

Upvotes: 5

Related Questions