gpt4 book ai didi

F# 自定义类型提供程序 : "Container type already set" error

转载 作者:行者123 更新时间:2023-12-04 15:02:01 25 4
gpt4 key购买 nike

最近我参加了 Keith Battochi 关于类型提供程序的教程,他在 MSDN 教程中介绍了 MiniCsv 类型提供程序的一个变体。不幸的是,我的笔记本电脑不可用,所以我不得不尽可能地手工写下代码。我相信我已经重新创建了类型提供程序,但我得到了

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()

谢谢你的帮助!

最佳答案

定义 'Row' 类型时需要使用另一个构造函数。现有的 ProvidedTypeDefinition 类型公开了两个构造函数:

  • (assembly, namespace, typename, base type) - 定义容器为命名空间的顶级类型。
  • (typename, basetype) - 定义应该添加到其他类型的嵌套类型。

  • 现在 Row 类型是使用第一个构造函数定义的,因此它被视为顶级类型。当此类型稍后作为嵌套添加到 WholeFileType 时,会引发异常。

    关于F# 自定义类型提供程序 : "Container type already set" error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11170446/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com