Поставщики типов F #: можете ли вы использовать поставщик типов в том же проекте, в котором он определен? - PullRequest
1 голос
/ 01 апреля 2020

Я следовал руководству о провайдерах типа 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

...