2015-04-08 108 views
3

我正在構建一個簡單的類型提供程序,但似乎在引用創建的類型時遇到問題。例如,給定F#類型提供程序引用自定義類型

namespace Adder 

type Summation = Summation of int 

module QuickAdd = 
    let add x y = x + y |> Summation 

我想作以下測試用例通:

module Adder.Tests 

open Adder 
open NUnit.Framework 

type Simple = QuickAddProvider<1, 2> 

[<Test>] 
let ``Simple sample is 3``() = 
    let foo = Simple() 
    Assert.AreEqual(foo.Sample, Summation 3) 

有以下類型供應商:

namespace Adder 

open Microsoft.FSharp.Core.CompilerServices 
open ProviderImplementation.ProvidedTypes 
open System.Reflection 

[<TypeProvider>] 
type public QuickAddProvider (config : TypeProviderConfig) as this = 
    inherit TypeProviderForNamespaces() 

    let ns = "Adder" 
    let asm = Assembly.GetExecutingAssembly() 
    let paraProvTy = ProvidedTypeDefinition(asm, ns, "QuickAddProvider", Some typeof<obj>) 

    let buildTypes (typeName:string) (args:obj[]) = 
    let num1 = args.[0] :?> int 
    let num2 = args.[1] :?> int 
    let tpType = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<obj>) 
    let result = QuickAdd.add num1 num2 
    let orig = ProvidedProperty("Sample", typeof<Summation>, GetterCode = (fun args -> <@@ result @@>)) 
    tpType.AddMember(orig) 
    tpType.AddMember(ProvidedConstructor([], InvokeCode = (fun args -> <@@() @@>))) 
    tpType 

    let parameters = 
    [ProvidedStaticParameter("Num1", typeof<int>) 
    ProvidedStaticParameter("Num2", typeof<int>)] 

    do paraProvTy.DefineStaticParameters(parameters, buildTypes) 
    do this.AddNamespace(ns, [paraProvTy]) 

[<TypeProviderAssembly>] 
do() 

我碰上測試文件意外的錯誤:

The type provider 'Adder.QuickAddProvider' reported an error in the context of provided type 'Adder.QuickAddProvider,Num1="1",Num2="2"', member 'get_Sample'. The error: Unsupported constant type 'Adder.Summation' 

隨着生成的文件下列錯誤:

The type "Summation" is not defined 
The namespace or module "Adder" is not defined 

測試案例彙編,並與int更換Summation類型時通過,所以我知道我的類提供商是不是可怕的錯誤。我是否需要以某種方式在某處「導入」Summation類型?

回答

6

此錯誤通常意味着您正在創建一個包含自定義類型值的引用。類型提供者中的引號只能包含基本類型的值 - 編譯器知道如何序列化這些類型 - 但它不能處理自定義類型。

在代碼段中,發生這種情況的位置:

let result = QuickAdd.add num1 num2 
let orig = ProvidedProperty("Sample", typeof<Summation>, GetterCode = (fun args -> 
    <@@ result @@>)) 

這裏,GetterCode返回包含不被支持Summation類型的值的報價。要做到這一點,你可以做很多事情 - 通常,你需要提出一些其他的引用表達式來產生你想要的值。

一種選擇是做計算報價,而不是外面:

<@@ QuickAdd.add num1 num2 @@> 

另一種選擇將是重新創建Summation值在報價:

let (Summation n) = result 
<@@ Summation n @@> 

這是有效的,因爲它只需要序列化原始值int值,然後生成對案例構造函數的調用。

+1

太棒了,感謝您的提示,我不知道限制報價。您是否知道Type Provider Starter Pack之外的此F#主題上的任何良好資源? **專家F#v3 **在類型提供商和報價方面似乎有點欠缺。 –