Извлечение типа делегата с использованием пользовательских типов из сборки, которая в данный момент создается

#f# #delegates #system.reflection #cil

#f# #делегаты #system.reflection #cil

Вопрос:

Я пытаюсь создать компилятор на F #, используя API, предоставляемый в System.Отражение.Излучение. Я сталкиваюсь с проблемой, когда пытаюсь создать функции (делегаты) для типов в сборке, которую я в настоящее время создаю. Пример перевода следующего класса Java (слегка измененная версия Java):

 class A extends Object {
    Integer x;
    A (Integer x) {
        super();
        this.x = x;
    }
    Function<A, Integer> fun() {
        return (A a) -> { return a.x; };
    }
}
  

Итак, мне нужно иметь возможность использовать систему.Тип функции<A, Integer> для генерации следующей инструкции CIL:

 newobj instance void class [mscorlib]System.Func`2<class tst.A,int32>::.ctor(object, native int) 
  

Код, генерирующий соответствующую инструкцию, является:

 let deleg = System.Linq.Expressions.Expression.GetDelegateType(types)
let constr = deleg.GetConstructor([|typeof<obj> ; typeof<nativeint>|])
ilGenerator.Emit(OpCodes.Newobj, constr) 
  

где types — массив System.Введите элементы. В случае Fun<A, Integer> массивом типов является [|typ ; typeof<int>|] , где тип объявлен как: let typ : System.Type = upcast typeBuilder . Однако это вызывает следующую ошибку:

 System.NotSupportedException: Specified method is not supported.
at System.Reflection.Emit.TypeBuilderInstantiation.GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetConstructor(BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
  

Если бы мне нужно было сгенерировать ту же инструкцию для функции, которая использует типы .NET, например Func<Integer, Целое число>, то приведенный выше код работает идеально (в данном случае используется массив типов types = [| typeof<int> ; typeof<int> |] ). Любые предложения, почему вышеупомянутое решение не работает, или любые другие альтернативы того, как получить систему.Тип TypeBuilder (который еще не закончил сборку) более чем приветствуется.

Способ создания типа для класса A заключается в:

 let typeBuilder = moduleBuilder.DefineType(typ, TypeAttributes.Public ||| TypeAttributes.Class)
typeBuilder.SetParent(typeof<obj>)
typeBuilder.DefineField("x", typeof<int>, FieldAttributes.Public)
let constrBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, [|typeof<int>|])
let methodBuilder = typeBuilder.DefineMethod("fun", MethodAttributes.Public)
let delegRetType =  System.Linq.Expressions.Expression.GetDelegateType([|typeof<obj> ; typeof<int>|]).GetConstructor([|typeof<obj> ; typeof<nativeint>|]).DeclaringType
methodBuilder.SetReturnType(delegRetType) 
methodBuilder.SetParameters([||])
//buildConstrBody - nothing special
//buildMethodBody - generating the instructions using the methodBuilder .GetILGenerator() - triggering the error described above
typeBuilder.CreateType()
  

Обратите внимание, что delegRetType на самом деле это Func<Объект, целое число> вместо Func<A, целое число>. Если я попытаюсь изменить его на последний, возникает та же ошибка…

Комментарии:

1. Это сложно отлаживать, потому что вы не предоставили общий доступ к коду, который мы могли бы попробовать запустить, но я заметил, что в сообщении об ошибке говорится Could not load type 'A' (...) because the parent type is sealed. . Для какого родительского типа вы используете A ? Это закрытый тип?

2. Нет, это не так, родительским элементом этого класса является класс Object, который просто расширяет систему F #. Тип, полученный из typeof<obj> . Но тип A имеет вложенный класс для инкапсуляции функции, который объявлен следующим образом: let nestedTypeBuilder = classTypeBuilder.DefineNestedType(cls, TypeAttributes.AutoClass ||| TypeAttributes.AnsiClass ||| TypeAttributes.Sealed ||| TypeAttributes.NestedPublic) , но ошибка сохраняется, даже если я удаляю модификатор sealed…

3. Я отредактировал сообщение, предоставив больше информации о коде. Ошибка с запечатанным родительским элементом больше не запускается (на самом деле не знаю, почему). Я надеюсь, что теперь мой вопрос более понятен, учитывая, что я опубликовал простой пример, который работает с. СЕТЕВЫЕ типы.

Ответ №1:

Если бы мне нужно было сгенерировать ту же инструкцию для функции, которая использует типы .NET, например Func<Integer, Целое число>, то приведенный выше код работает идеально (в данном случае используется массив типов types = [| typeof<int> ; typeof<int> |] ).

TypeBuilder наследуется от Type , поэтому вы просто передаете экземпляр, представляющий тип, который вы создаете, когда хотите ссылку на этот тип. Другими словами, требуемый массив является types = [| typeBuilder :> System.Type; typeof<int> |]

Комментарии:

1. но почему upcast typeBuilder это также не работает?

Ответ №2:

Это действительно работает, если массив построен следующим образом:

 types = [| typeBuilder.GetType(); typeof<int> |]