Skip to content

Instantly share code, notes, and snippets.

@odytrice
Created May 24, 2020 21:55
Show Gist options
  • Save odytrice/313b2107f6ad52de12ae89f35941d4b2 to your computer and use it in GitHub Desktop.
Save odytrice/313b2107f6ad52de12ae89f35941d4b2 to your computer and use it in GitHub Desktop.
Simple F# Type Provider for Mutable Records
namespace TestProvider.Provided
open System.Reflection
open FSharp.Core.CompilerServices
open ProviderImplementation.ProvidedTypes
open System.Collections.Generic
open Microsoft.FSharp.Quotations
[<TypeProvider>]
type SampleProvider(config) as this =
inherit TypeProviderForNamespaces(config)
let ns = "SampleProvider.Provided"
let asm = Assembly.GetExecutingAssembly()
let addProperty (name: string) (_: 'T) (baseType: ProvidedTypeDefinition) =
let getter (args: Quotations.Expr list) = <@@ ((%%args.[0]:obj) :?> Dictionary<string,obj>).[name] :?> 'T @@>
let setter (args: Quotations.Expr list) = <@@ ((%%args.[0]:obj) :?> Dictionary<string,obj>).[name] <- (%%args.[1]:'T) @@>
let myInstanceProperty =
ProvidedProperty(name,
typeof<'T>,
isStatic = false,
getterCode = getter,
setterCode = setter)
baseType.AddMember myInstanceProperty
baseType
let addMethod (method: ProvidedMethod) (baseType: ProvidedTypeDefinition) =
baseType.AddMember method
baseType
let createType name (parameters: obj[]) =
let aString = parameters.[0] :?> string
let myType = ProvidedTypeDefinition(asm, ns, name, Some typeof<obj>, isErased = true)
let props = [
"FirstName"
"LastName"
"Date"
]
let propExpr = Expr.NewArray(typeof<string>, props |> List.map (Expr.Value))
let constructor =
<@@
let items = %%propExpr:string[]
let d = Dictionary<string, obj>()
for item in items do
d.Add(item, null)
d
@@>
let ctor = ProvidedConstructor([], invokeCode = fun args -> constructor)
myType.AddMember(ctor)
let greetMethod (args: Expr list) =
<@@
let state = (%%args.[0]:obj) :?> Dictionary<string,obj>
let firstName = state.["FirstName"]:?> string
let lastName = state.["LastName"] :?> string
let date = state.["Date"] :?> System.DateTime
sprintf "Hello my name is %s %s, The time is %O" firstName lastName date
@@>
let greet = ProvidedMethod("Greet",[],typeof<string>,isStatic = false, invokeCode = greetMethod)
myType
|> addProperty props.[0] Unchecked.defaultof<string>
|> addProperty props.[1] Unchecked.defaultof<string>
|> addProperty props.[2] Unchecked.defaultof<System.DateTime>
|> addMethod greet
let provider =
ProvidedTypeDefinition(asm,ns, "RecordProvider", Some typeof<obj>)
let parameters =
[ ProvidedStaticParameter("Name", typeof<string>) ]
do
provider.DefineStaticParameters(parameters, createType)
this.AddNamespace(ns, [ provider ])
[<assembly: TypeProviderAssembly>]
do()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment