2012-06-23 19 views
6

हाल ही में मैंने टाइप प्रदाताओं पर कीथ बटोतोई द्वारा एक ट्यूटोरियल में भाग लिया, जिसमें उन्होंने एमएसडीएन ट्यूटोरियल में मिनीसीएसवी प्रकार प्रदाता का एक संस्करण पेश किया। दुर्भाग्यवश, मेरा लैपटॉप उपलब्ध नहीं था, इसलिए मुझे हाथ से कोड लिखना पड़ा और साथ ही मैं कर सकता था। मेरा मानना ​​है कि मैं प्रकार प्रदाता निर्मित किया है, लेकिन मैंएफ # कस्टम प्रकार प्रदाता: "कंटेनर प्रकार पहले से सेट है" त्रुटि

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 प्रकार दो कंस्ट्रक्टर्स को उजागर करता है:

  • (विधानसभा, नाम स्थान, typename, आधार प्रकार) - शीर्ष स्तर प्रकार जिसका कंटेनर नाम का स्थान परिभाषित करता है।
  • (टाइपनाम, बेसटाइप) - नेस्टेड प्रकार को परिभाषित करता है जिसे किसी अन्य प्रकार में जोड़ा जाना चाहिए।

अब पंक्ति प्रकार को पहले कन्स्ट्रक्टर का उपयोग करके परिभाषित किया गया है, इसलिए इसे शीर्ष स्तर के प्रकार के रूप में माना जाता है। अपवाद तब उठाया जाता है जब इस प्रकार को बाद में पूर्णफाइल टाइप में नेस्टेड के रूप में जोड़ा जाता है।

+0

धन्यवाद! मदद की सराहना करें। –