F # - генерировать простой пустой тип из строки во время компиляции - PullRequest
0 голосов
/ 10 мая 2018

Мне было интересно, возможно ли сгенерировать что-то похожее на провайдера простого типа (запись или объединение, без членов, только совпадающее имя с именем строки) из строки во время компиляции.

смешивание этого

http://www.readcopyupdate.com/blog/2014/09/18/faking-typeclasses-using-static-type-constraints.html

и этого

Создание случая дискриминированного объединения из строки

или аналогичного подхода к записитипы.

то, что я хотел бы получить, например (необязательно при том же подходе):

[<Literal>]
let myTypeName = "One"

type SingleStringTypeProvider = ... (here implementation)


type Provided = SingleStringTypeProvider<singleString>


let typeName = typeof<Provided.One>.Name

окончательный результат: один - это тип во время компиляции (а неметод или функция)

РЕДАКТИРОВАТЬ

Как было предложено в первом ответе (большое спасибо:)), я пытался реализовать его с предоставленным типом, но я все еще борюсь, пытаясьполучить доступ к провайдеру типов из моего файла сценария, по-видимому, я вижу только созданный тип, но не сам провайдер типа?

module SimpleStringProvider

open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices

[<TypeProvider>]
type SingleStringTypeProvider (config : TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces (config)

    let asm = System.Reflection.Assembly.GetExecutingAssembly()
    let ns = "SimpleStringProvider"
    let stringProvider = ProvidedTypeDefinition(asm, ns, "SingleStringTypeProvider", Some(typeof<obj>))

    // Define one static parameter with type name
    let parameter = ProvidedStaticParameter("TypeName", typeof<string>)
    do stringProvider.DefineStaticParameters([parameter], fun typeName args ->
    // Create the main type (this corresponds to `Provided`)    
    let resTy = ProvidedTypeDefinition(asm, ns, typeName, Some(typeof<obj>))

    // Add a nested type as a member using the name from the parameter
    let typeName = args.[0] :?> string
    ProvidedTypeDefinition(typeName, None)
    |> resTy.AddMember

    resTy )


[<assembly:TypeProviderAssembly>]
do ()

и вот код в моем файле script.fsx, вероятно, я делаю несколько глупоошибки, я думаю.

#r @".\testType\SimpleStringProvider.dll"

open SimpleStringProvider

type x = SimpleStringProvider.SingleStringTypeProvider<"test">

ОШИБКА в файле script.fsx

Неуниверсальный тип 'SimpleStringProvider.SingleStringTypeProvider' не ожидает никаких аргументов типа, но здесь дается 1 аргумент типа(s)

1 Ответ

0 голосов
/ 10 мая 2018

Вы можете предоставить вложенные типы, которые могут быть основаны на статическом параметре.В вашем примере Provided является типом, а Provided.One может быть вложенным типом.

Чтобы сделать это, вы можете написать что-то вроде этого:

[<TypeProvider>]
type public SingleStringTypeProvider(cfg:TypeProviderConfig) as this =
  inherit TypeProviderForNamespaces()

  // Generate namespace and the main type provider
  let asm = System.Reflection.Assembly.GetExecutingAssembly()
  let ns = "Samples"
  let stringProvider = ProvidedTypeDefinition(asm, ns, "SingleStringTypeProvider", Some(typeof<obj>))

  // Define one static parameter with type name
  let parameter = ProvidedStaticParameter("TypeName", typeof<string>)
  do stringProvider.DefineStaticParameters([parameter], fun typeName args ->
    // Create the main type (this corresponds to `Provided`)    
    let resTy = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<IniFile>)

    // Add a nested type as a member using the name from the parameter
    let typeName = args.[0] :?> string
    ProvidedTypeDefinition(typeName, None)
    |> resTy.AddMember

    resTy )

[<assembly:TypeProviderAssembly>]
do()

Я не проверял это, поэтому вам может потребоваться внести некоторые изменения, но я думаю, что это должно сработать.

...