4

デリゲート型がinternalの場合、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モジュールが「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)
       ...

おそらくここで重要な点を見逃しているのかもしれませんが、現在、これが起こっている理由はわかりません。

4

1 に答える 1

5

F#とC#は、デリゲートのInvokeメソッドを発行するために異なる戦略を使用します。C#で同様のデリゲートを定義しようとすると、デリゲートタイプは内部になりますが、パブリックInvokeメソッドを使用します。F#は、宣言型と同じ可視性でInvokeメソッドを定義します。Expression.Lambdaのコードが、指定されたデリゲート型でInvokeメソッドを見つけようとすると、すべてのコンパイラがC#と同様に動作すると想定して、パブリックメソッドのみを検索します。

于 2012-05-29T23:11:03.000 に答える