6
最近我參加了Keith Battochi關於類型提供程序的教程,其中他在MSDN教程中介紹了MiniCsv類型提供程序的變體。不幸的是,我的筆記本電腦不可用,所以我不得不用手寫下代碼。我相信我已經重新類型供應商,但我越來越F#自定義類型提供程序:「容器類型已設置」錯誤
error FS3033: The type provider 'CsvFileTypeProvider+CsvFileTypeProvider' reported an error: container type for 'CsvFileProvider.Row' was already set to 'CsvFileProvider.CsvFile,Filename="events.csv"
當我在看代碼,我看不到我如何加入行類型的容器兩次(或一些其他容器)。刪除代碼的選定行不起作用。
這裏是我如何調用代碼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()
感謝您的幫助!
謝謝!感謝幫助。 –