Поставщики типов F# — создание экземпляров вложенных свойств

Я пытаюсь создать свой первый поставщик типов игрушек. Чего я пытаюсь достичь, так это иметь динамически генерируемые свойства динамически генерируемых типов.

collection 
|> getItems
|> Seq.map(fun mapItem ->            
    let nestedType = ProvidedTypeDefinition(assembly, ns, "MyNestedType", None)
    let ctor = ProvidedConstructor(List.Empty)
    nestedType.AddMember ctor
    mapItem.Value 
        |> Seq.map(fun pair -> 
        ProvidedProperty(fst(pair), typeof<string>,
            GetterCode = fun [_] -> <@@ snd(pair) @@>))
        |> Seq.toList
        |> nestedType.AddMembers


    ProvidedProperty(mapItem.Key, nestedType,
        GetterCode = fun [map] ->   
            // ?? Runtime Exception   
            let inst = nestedType.GetConstructors().[0].Invoke([||])             
            <@@ inst @@>
                ))
    |> Seq.toList
    |> ty.AddMembers      

ty

Как мне создать экземпляр динамически сгенерированного типа?


person mickl    schedule 22.04.2016    source источник


Ответы (2)


Я предполагаю, что это поставщик стирающего типа (это самые простые, поэтому они лучше подходят для начала). Если это не так, то не обращайте внимания на мой ответ.

В GetterCode вам не нужно создавать экземпляр вложенного предоставленного типа. Вам просто нужно создать экземпляр того типа, к которому он затирается.

В вашем случае nestedType стирается до None, поэтому конструктору просто нужно создать значение System.Object, поэтому вы сможете использовать:

ProvidedProperty(mapItem.Key, nestedType,
    GetterCode = fun [self] -> <@@ obj() @@>)

На самом деле вы, вероятно, захотите стереть какой-либо тип, который позволит вам сохранить некоторые данные, к которым должен обращаться вложенный тип. Если бы вложенный тип был стерт, скажем, до MyRuntimeType, вы могли бы написать:

let parameter = mapItem.WhateverYouWantHere
ProvidedProperty(mapItem.Key, nestedType,
    GetterCode = fun [self] -> <@@ MyRuntimeType(parameter) @@>)

Обратите внимание, что я использую let для захвата значения примитивного типа parameter, чтобы компилятор мог сериализовать цитату (вы не можете захватывать сложные типы объектов в цитате).

person Tomas Petricek    schedule 22.04.2016
comment
Спасибо, теперь я понимаю, как работает стертый шрифт. Проблема в том, что я не знаю имен свойств во время компиляции поставщика типов, поэтому, если я не ошибаюсь, я могу стереть только объект. - person mickl; 22.04.2016
comment
Я пытаюсь добиться только того, чтобы иметь что-то вроде этого: createdType.dynamically_generated_prop.dynamically_generated_prop_nested, при использовании провайдера - person mickl; 22.04.2016

Здесь вы пытаетесь создать экземпляр своего типа при создании поставщика, а затем включить этот новый экземпляр в тело свойства. Должно быть совершенно ясно, что вы не можете создать экземпляр предоставленного типа, пока не закончите его предоставление.

Что вы действительно хотите сделать, так это взять предоставленный вами конструктор и построить цитату, которая его вызывает. Вы не можете заставить компилятор построить цитату за вас, потому что для того, чтобы компилятор скомпилировал тело цитаты, ему нужно «увидеть» все типы/методы/функции внутри, а ваш тип еще не готов. Но вы можете создать предложение вручную, используя различные конструкторы в разделе Quotations.Expr. В данном случае подходит NewObject:

    GetterCode = fun [map] -> Expr.NewObject (ctor, [])
person Fyodor Soikin    schedule 22.04.2016