Reputation: 1024
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
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