Я следовал руководству о провайдерах типа F # там , исходный код доступен здесь .
Program.fs
:
open System.Reflection
open Microsoft.FSharp.Core.CompilerServices
open ProviderImplementation.ProvidedTypes
[<TypeProvider>]
type StringTypeProvider(config: TypeProviderConfig) as this =
inherit TypeProviderForNamespaces(config)
let namespaceName = "Samples.StringTypeProvider"
let thisAssembly = Assembly.GetExecutingAssembly()
let staticParams = [ProvidedStaticParameter("value", typeof<string>)]
let t = ProvidedTypeDefinition(thisAssembly, namespaceName, "StringTyped", Some typeof<obj>, hideObjectMethods = true)
do t.DefineStaticParameters(
parameters = staticParams,
instantiationFunction = (fun typeName paramValues ->
match paramValues with
| [| :? string as value |] ->
let ty = ProvidedTypeDefinition(
thisAssembly,
namespaceName,
typeName,
Some typeof<obj>
)
let lengthProp = ProvidedProperty(
"Length",
typeof<int>,
getterCode = fun _ -> <@@ value.Length @@>
)
ty.AddMember lengthProp
let charProps = value
|> Seq.map(fun c ->
let p = ProvidedProperty(
c.ToString(),
typeof<char>,
getterCode = fun _ -> <@@ c @@>
)
let doc = sprintf "The char %s" (c.ToString())
p.AddXmlDoc doc
p
)
|> Seq.toList
ty.AddMembersDelayed (fun () -> charProps)
let sanitized = value.Replace(" ","")
let valueProp = ProvidedProperty(
sanitized,
typeof<string>,
getterCode = fun _ -> <@@ value @@>
)
valueProp.AddXmlDoc "This is the value that you gave me to start with"
ty.AddMember valueProp
let ctor = ProvidedConstructor(
parameters = [],
invokeCode = fun args -> <@@ value :> obj @@>
)
ctor.AddXmlDoc "Initializes a the awesomes"
ty.AddMember ctor
let reverser = ProvidedMethod(
methodName = "Reverse",
parameters = [],
returnType = typeof<string>,
invokeCode = (fun _ ->
<@@
value
|> Seq.map (fun x -> x.ToString())
|> Seq.toList
|> List.rev
|> List.reduce (fun acc el -> acc + el)
@@>))
ty.AddMember reverser
ty
| _ -> failwith "No idea what you're doing"
)
)
do this.AddNamespace(namespaceName, [t])
[<assembly:TypeProviderAssembly>]
do()
open Samples.StringTypeProvider
type snowman = Samples.StringTypeProvider.StringTyped< @"☃" >
let doYouWantToBuildASnowman = snowman()
doYouWantToBuildASnowman.``☃``
[<EntryPoint>]
let main _ =
0
У меня есть ошибки ниже:
<FSharpPlayground>\Program.fs:3819 The namespace or module 'Samples' is not defined.
<FSharpPlayground>\Program.fs:3862 The namespace or module 'Samples' is not defined.
<FSharpPlayground>\Program.fs:3975 The type 'Object' does not define the field, constructor or member '☃'.
Что имеет смысл, но есть ли обходной путь, чтобы иметь возможность использовать провайдер типа F #, определенный в том же проекте, в котором он определен?
[EDIT 1]
Даже если я помещу все определение StringTypeProvider
в другой файл с namespace Samples.StringTypeProvider
, а затем импортирую его в Program.fs
с open Samples.StringTypeProvider
, это не сработает .
Например, набрав type snowman = Samples.StringTypeProvider.StringTyped< @"☃" >
, я получаю:
Program.fs(3, 43): [FS0039] The type 'StringTyped' is not defined in 'Samples.StringTypeProvider'. Maybe you want one of the following:
StringTypeProvider
[РЕДАКТИРОВАТЬ 2]
Я пытался отделить определение поставщика типа и место где это используется, но я все еще получаю ошибки: https://github.com/ehouarn-perret/Issues.TypeProviders