2012-06-23 4 views
6

最近、私はKeith Battochi氏のタイププロバイダのチュートリアルに参加し、MSDNチュートリアルでMiniCsvタイププロバイダの変種を紹介しました。残念ながら、私のラップトップは利用できませんでしたので、できるだけでなく手でコードを書き留めなければなりませんでした。私は、タイププロバイダを再作成しましたと信じて、私は、私はコードを見たとき、私は(またはいくつかの2回、コンテナへの行のタイプを追加しているかを確認することはできません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() 

ありがとう!

答えて

6

'行'タイプを定義するときは、別のコンストラクタを使用する必要があります。既存のProvidedTypeDefinition型は、2つのコンストラクタを公開します。

  • (アセンブリ、名前空間、型名、基本型) - コンテナが名前空間であるトップレベル型を定義します。
  • (typename、basetype) - 別の型に追加するネスト型を定義します。

Now行タイプは最初のコンストラクタを使用して定義されるため、最上位タイプとして扱われます。この型が後でwholeFileTypeにネストされるときに例外が発生します。

+0

ありがとうございます!ヘルプをよろしくお願いいたします。 –

関連する問題