2012-06-23 18 views
6

Niedawno uczestniczyłem w kursie Keitha Battochiego dotyczącego dostawców typów, w którym przedstawił wariant dostawcy typu MiniCsv w samouczku MSDN. Niestety, mój laptop nie był dostępny, więc musiałem zapisać kod ręcznie, jak tylko mogłem. Wierzę, że już odtworzone dostawcy typu, ale jestem corazF # dostawca typu niestandardowego: "Typ kontenera już ustawiony" błąd

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

Kiedy patrzę na kod, nie widzę jak Dodaję typ rząd do pojemnika dwukrotnie (lub niektóre inny pojemnik). Usunięcie wybranych linii kodu nie pomoże.

Oto jak dzwonię kod w FSI:

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

I Oto kod się:

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

Dzięki za wszelką pomoc!

Odpowiedz

6

należy użyć innego konstruktora podczas definiowania typu "Wiersz". Istniejący typ ProvidedTypeDefinition udostępnia dwa konstruktory:

  • (montaż, przestrzeń nazw, nazwa-pliku, typ podstawowy) - określa typ najwyższego poziomu, którego kontenerem jest przestrzeń nazw.
  • (typename, typ podstawowy) - definiuje typ zagnieżdżony, który należy dodać do innego typu.

Teraz Typ wiersza definiowany jest za pomocą pierwszego konstruktora, dlatego jest traktowany jako typ najwyższego poziomu. Wyjątek jest wywoływany, gdy ten typ jest później dodawany do elementu wholeFileType jako zagnieżdżony.

+0

Dzięki! Doceń pomoc. –

Powiązane problemy