I'm having a hard time deciphering the "Providing Generated Types" section of the Type Provider Tutorial. The tutorial provides the following specification.
"You must also call ConvertToGenerated on a root provided type whose nested types form a closed set of generated types. This call emits the given provided type definition and its nested type definitions into an assembly and adjusts the Assembly property of all provided type definitions to return that assembly. The assembly is emitted only when the Assembly property on the root type is accessed for the first time. The host F# compiler does access this property when it processes a generative type declaration for the type."
I do not know where to place the ConvertToGenerated call and I'm not sure on the requirements of the assembly file name parameter. Can someone provide an example? Thanks.
After some help from the F# team I solved my problem. This is what I did.
namespace Types
open System
open System.Data
open System.IO
open System.Linq
open System.Data.Linq
open Microsoft.FSharp.Data.TypeProviders
open Microsoft.FSharp.Linq
open Microsoft.FSharp.TypeProvider.Emit
open Microsoft.FSharp.Core.CompilerServices
type DatabaseSchema =
SqlDataConnection<"Data Source=(local);Initial Catalog=Test;Integrated Security=SSPI;">
[<TypeProvider>]
type public MeasureTypeProvider(cfg:TypeProviderConfig) as this =
inherit TypeProviderForNamespaces()
let assembly = System.Reflection.Assembly.GetExecutingAssembly()
let typesNamespace = "Types.Domain"
let providedTypeBuilder = ProvidedTypeBuilder.Default
let db = DatabaseSchema.GetDataContext()
let types =
query { for m in db.Table do select m }
|> Seq.map(fun dataEntity ->
let className:string = dataEntity.Identifier
let providedTypeDefinition =
ProvidedTypeDefinition(className = className,
baseType = Some typeof<obj>,
IsErased=false)
providedTypeDefinition.AddMember(
ProvidedConstructor([], InvokeCode = fun [] -> <@@ obj() @@>))
providedTypeDefinition
) |> Seq.toList
let rootType =
let providedTypeDefinition =
ProvidedTypeDefinition(assembly,
typeNamespace,
"DomainTypes",
Some typeof<obj>,
IsErased=false)
providedTypeDefinition.AddMembersDelayed(fun () -> types)
this.AddNamespace(typesNamespace, [providedTypeDefinition])
providedTypeDefinition
let path = Path.GetDirectoryName(assembly.Location) + @"\GeneratedTypes.dll"
do rootMeasureType.ConvertToGenerated(path)
[<assembly:TypeProviderAssembly>]
do()
The TypeProvider.Emit framework automatically cleans up the generated assembly. Comment out the following statement if you want it to stick around.
File.Delete assemblyFileName
One other gotcha I found is that while I was able to provide types that derive from value types (like decimal) when IsErased=true, I was not able to provide these derived types when IsErased=false. This is because value types are sealed so it is is not possible to generate a "real" type that derives from a value type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With