2012-05-29 3 views
4

У меня возникли проблемы с компиляцией выражения лямбда для свойства getter в F #, если тип делегата внутренний. Это то, что функция выглядит следующим образом:Скомпилировать лямбда-выражение с внутренним типом делегата

// 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 определяется как «внутренний»):

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) 
     ... 

Возможно, у меня отсутствует важный момент, но в настоящее время я не вижу причин, почему это происходит.

+0

Вы получаете это исключение только из FSI или получаете его из правильно скомпилированного приложение также? – ildjarn

+0

@ildjarn: Я получаю это исключение из правильно скомпилированного кода (в некоторых модульных тестах). – kongo2002

+0

Пожалуйста, не приписывайте свои заголовки «F #:» и тому подобное. Для этого нужны теги. –

ответ

5

F # и C# используют разные стратегии для испускания метода Invoke для делегатов. Если вы попытаетесь определить аналогичный делегат в C#, то он - тип делегата будет внутренним, но с общедоступным методом Invoke. F # определяет метод Invoke с той же видимостью, что и тип объявления. Когда код в Expression.Lambda пытается найти метод Invoke в заданном типе делегата, он смотрит только на общедоступные методы, предполагая, что все компиляторы ведут себя аналогично C#

+0

А, я вижу, это имеет смысл. Это то, что вам просто нужно знать, я думаю :-) – kongo2002