#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> |]