使用内部委托类型编译lambda表达式

时间:2012-05-29 22:31:37

标签: .net reflection f#

如果委托类型是 internal ,我在为F#中的属性getter编译lambda表达式时遇到了一些麻烦。这就是函数的样子:

// 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()

如果我用公共类调用此方法,我会得到一个像这样的异常(仅当ReflectionHelpers模块定义为'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)
       ...

可能我在这里错过了一个重要的观点,但目前我看不出为什么会发生这种情况。

1 个答案:

答案 0 :(得分:5)

F#和C#使用不同的策略为委托发出Invoke方法。如果您尝试在C#中定义类似的委托 - 委托类型将是内部但具有公共Invoke方法。 F#定义了与声明类型具有相同可见性的Invoke方法。当Expression.Lambda中的代码尝试在给定委托类型中查找Invoke方法时,它仅查找公共方法,假设所有编译器的行为类似于C#