2012-06-23 27 views
6

Gần đây tôi đã tham dự hướng dẫn của Keith Battochi về nhà cung cấp loại, trong đó ông đã giới thiệu một biến thể của nhà cung cấp loại MiniCsv trong hướng dẫn MSDN. Thật không may, máy tính xách tay của tôi không có sẵn, vì vậy tôi đã phải viết mã bằng tay cũng như tôi có thể. Tôi tin rằng tôi đã tái tạo các nhà cung cấp loại, nhưng tôi nhận đượcNhà cung cấp loại tùy chỉnh F #: Lỗi "Loại vùng chứa đã được đặt"

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

Khi tôi nhìn vào mã này, tôi không thể nhìn thấy như thế nào tôi thêm loại Row để container hai lần (hoặc một số container khác). Việc xóa các dòng mã đã chọn không có tác dụng.

Đây là cách tôi đang kêu gọi các mã trong FSI:

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

Và đây là mã bản thân:

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

Nhờ sự giúp đỡ!

Trả lời

6

bạn cần phải sử dụng một hàm tạo khác khi xác định loại 'Hàng'. Loại ProvisionTypeDefinition hiện có cho thấy hai nhà thầu:

  • (lắp ráp, không gian tên, typename, loại cơ sở) - xác định loại cấp cao nhất có vùng chứa là không gian tên.
  • (typename, basetype) - xác định loại lồng nhau sẽ được thêm vào loại khác.

Bây giờ loại hàng được xác định bằng cách sử dụng hàm tạo đầu tiên để nó được coi là loại cấp cao nhất. Ngoại lệ được nâng lên khi loại này sau đó được thêm vào tệp fullFileType dưới dạng lồng nhau.

+0

Cảm ơn! Đánh giá cao sự trợ giúp. –

Các vấn đề liên quan