Поставщик настраиваемого типа F #: тип контейнера уже установлен, ошибка

Недавно я посетил обучающий курс Кейта Батточи по поставщикам типов, в котором он представил вариант поставщика типов MiniCsv в учебнике MSDN. К сожалению, мой ноутбук был недоступен, поэтому мне пришлось писать код вручную, насколько я мог. Кажется, я воссоздал поставщик типов, но я получаю

error FS3033: The type provider 'CsvFileTypeProvider+CsvFileTypeProvider' reported an error: container type for 'CsvFileProvider.Row' was already set to 'CsvFileProvider.CsvFile,Filename="events.csv"

Когда я смотрю на код, я не вижу, как я дважды добавляю тип Row в контейнер (или в какой-то другой контейнер). Удаление выбранных строк кода не помогает.

Вот как я вызываю код в fsi:

#r "CsvFileTypeProvider.dll"
open CsvFileProvider
let eventInfos = new CsvFile<"events.csv">() ;;

А вот и сам код:

module CsvFileTypeProvider
open Samples.FSharp.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices

let getType str =
    if System.DateTime.TryParse(str, ref Unchecked.defaultof<_>) then
        typeof<System.DateTime>, (fun (str:Quotations.Expr) -> <@@ System.DateTime.Parse(%%str) @@>)
    elif System.Int32.TryParse(str, ref Unchecked.defaultof<_>) then
        typeof<System.Int32>, (fun (str:Quotations.Expr) -> <@@ System.Int32.Parse(%%str) @@>)
    elif System.Double.TryParse(str, ref Unchecked.defaultof<_>) then
        typeof<System.Double>, (fun (str:Quotations.Expr) -> <@@ System.Double.Parse(%%str) @@>)
    else
        typeof<string>, (fun (str:Quotations.Expr) -> <@@ %%str @@>)

[<TypeProvider>]
type CsvFileTypeProvider() =
    inherit TypeProviderForNamespaces()

    let asm = typeof<CsvFileTypeProvider>.Assembly
    let ns = "CsvFileProvider"

    let csvFileProviderType = ProvidedTypeDefinition(asm, ns, "CsvFile", None)
    let parameters = [ProvidedStaticParameter("Filename", typeof<string>)]

    do csvFileProviderType.DefineStaticParameters(parameters, fun tyName [| :? string as filename |] ->
        let rowType = ProvidedTypeDefinition(asm, ns, "Row", Some(typeof<string[]>))

        let lines = System.IO.File.ReadLines(filename) |> Seq.map (fun line -> line.Split(','))
        let columnNames = lines |> Seq.nth 0
        let resultTypes = lines |> Seq.nth 1 |> Array.map getType

        for idx in 0 .. (columnNames.Length - 1) do
            let col = columnNames.[idx]
            let ty, converter = resultTypes.[idx]
            let prop = ProvidedProperty(col, ty)
            prop.GetterCode <- fun [row] -> converter <@@  (%%row:string[]).[idx] @@>
            rowType.AddMember(prop)

        let wholeFileType = ProvidedTypeDefinition(asm, ns, tyName, Some(typedefof<seq<_>>.MakeGenericType(rowType)))
        wholeFileType.AddMember(rowType)

        let ctor = ProvidedConstructor(parameters = []) // the *type* is parameterized but the *constructor* gets no args
        ctor.InvokeCode <- //given the inputs, what will we get as the outputs? Now we want to read the *data*, skip the header
            fun [] -> <@@ System.IO.File.ReadLines(filename) |> Seq.skip 1 |> Seq.map (fun line -> line.Split(','))  @@>
        wholeFileType.AddMember(ctor)
        wholeFileType
        )

    do base.AddNamespace(ns, [csvFileProviderType])

[<TypeProviderAssembly>]
do()

Спасибо за любую помощь!


person Paul Blair    schedule 23.06.2012    source источник


Ответы (1)


вам нужно использовать другой конструктор при определении типа «Строка». Существующий тип ProvidedTypeDefinition предоставляет два конструктора:

  • (сборка, пространство имен, имя типа, базовый тип) — определяет тип верхнего уровня, контейнером которого является пространство имен.
  • (typename, basetype) — определяет вложенный тип, который должен быть добавлен к какому-то другому типу.

Теперь тип строки определяется с помощью первого конструктора, поэтому он рассматривается как тип верхнего уровня. Исключение возникает, когда этот тип позже добавляется в wholeFileType как вложенный.

person desco    schedule 23.06.2012