I'm trying to build my first toy-like Type Provider. What I'm trying to achieve is to have dynamically generated properties of dynamically generated types.
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
How should I instantiate dynamically generated type ?
I'm assuming this is an erasing type provider (those are the easy ones, so they're better choice for getting started). If that's not the case, then disregard my answer.
In the GetterCode
, you do not need to create instance of the nested provided type. You just need to create an instance of the type that it is erased to.
In your case, nestedType
is erased to None
and so the constructor just needs to create a System.Object
value, so you should be able to use:
ProvidedProperty(mapItem.Key, nestedType,
GetterCode = fun [self] -> <@@ obj() @@>)
In reality, you'll probably want to erase to some type that lets you keep some data that the nested type is supposed to access. If the nested type was erased to, say, MyRuntimeType
, you could then write:
let parameter = mapItem.WhateverYouWantHere
ProvidedProperty(mapItem.Key, nestedType,
GetterCode = fun [self] -> <@@ MyRuntimeType(parameter) @@>)
Note that I'm using let
to capture the value of the primitive parameter
type, so that the compiler can serialize the quotation (you cannot capture complex object types in a quotation).