2015-11-07 31 views
0

我想生成一個帶有靜態函數的類型,然後我可以在使用屬性反射定義的函數中使用該函數。在我看來,一種將某些東西轉換成FSharp類型的方便方法,使用FSharp組合功能和類型的域,並將組合的代碼吐回到它的本機形式,從而獲得了類型檢查,VS智能感知,高階函數等,試圖讓我開始有這種類型的供應商,這主要是受複製>從各種文章在報價中是否可以使用提供的類型 - TypeProvider調用是否出現在ReflectedDefinition函數中?

[<TypeProvider>] 
type CSoundTypeProvider(config: TypeProviderConfig) as this = 

    inherit ProvidedTypes.TypeProviderForNamespaces() 

    let namespaceName = "TestNamespace" 
    let thisAssembly = Assembly.GetExecutingAssembly() 

// config. 

    let intType = typeof<int> 
    let providedParam = ProvidedTypes.ProvidedParameter("prm", intType) 
    let providedFunction = ProvidedTypes.ProvidedMethod("TestMethod", [providedParam], intType, IsStaticMethod=true 
            , InvokeCode = fun args -> 
                // The 'args' parameter represents expressions that give us access to the 
                // instance on which the method is invoked and other parameters (if there are more) 
                let instance = args.[0] 
                // Now we can return quotation representing a call to MethodInfo 'p' with 'instance' 
                instance) 
    let csoundProvidedWrapper = ProvidedTypes.ProvidedTypeDefinition(thisAssembly, namespaceName, "TestType", None) 
    do csoundProvidedWrapper.AddMember(providedFunction) 
    do this.AddNamespace(namespaceName, [csoundProvidedWrapper]) 

而與此測試它粘貼反映定義:

[<ReflectedDefinition>] 
let myfn i j = 
    let k = i * j 
    let x = k + 2 
    let f = TestNamespace.TestType.TestMethod k 
    let ret = f + 2 
    ret 

我解析反映的定義如下:

<@ myfn @> |> println 

的println是一個函數(來自另一篇文章複製),其具有許多有源圖案的像Patterns.Call解析報價(無,DerivedPatterns.MethodWithReflectedDefinition(N),expList),其爲我提供的所有代碼的experssion樹,除了提供的靜態方法。我試圖做甚至可能嗎?如果是這樣,有什麼積極的模式,我會從我這裏的println函數錯過:

let println expr = 
    let rec print expr = match expr with 
     | Patterns.Application(expr1, expr2) -> 
      // Function application. 
      print expr1 
      printf " " 
      print expr2 
     | Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList) -> 
      print n 
     | Patterns.Call(exprOpt, methodInfo, exprList) -> 
      // Method or module function call. 
      match exprOpt with 
      | Some expr -> print expr 
      | None -> printf "%s" methodInfo.DeclaringType.Name 
      printf ".%s(" methodInfo.Name 
      if (exprList.IsEmpty) then printf ")" else 
      print exprList.Head 
      for expr in exprList.Tail do 
       printf "," 
       print expr 
      printf ")" 
     | DerivedPatterns.Int32(n) -> 
      printf "%d" n 
     | Patterns.Lambda(param, body) -> 
      // Lambda expression. 
      printf "fun (%s:%s) -> " param.Name (param.Type.ToString()) 
      print body 
     | Patterns.Let(var, expr1, expr2) -> 
      // Let binding. 
      if (var.IsMutable) then 
       printf "let mutable %s = " var.Name 
      else 
       printf "let %s = " var.Name 
      print expr1 
      printf " in " 
      print expr2 
     | Patterns.PropertyGet(_, propOrValInfo, _) -> 
      printf "%s" propOrValInfo.Name 
     | DerivedPatterns.String(str) -> 
      printf "%s" str 
     | Patterns.Value(value, typ) -> 
      printf "%s" (value.ToString()) 
     | Patterns.Var(var) -> 
      printf "%s" var.Name 
     | _ -> printf "%s" (expr.ToString()) 
    print expr 

如果我不能做到這一點,你會推薦什麼樣的方式產生FSharp定義,我可以在報價單使用?我已經在很大程度上受到了FunScript項目的影響,但是希望避免看起來每個Typescript定義必須被編譯到一個單獨的DLL中的步驟。

回答

2

大多數類型的提供商演示使用擦除類型提供程序不生成實際的.NET類型。當您使用擦除類型提供程序時,生成的方法是已被刪除,並替換爲您在方法InvokeCode中提供的代碼。

比方說,你有一個方法Foo"Foo"擦除到someFunc作爲參數:

myObj.Foo() ~> someFunc(myObj, "Foo") 

在報價單,您也將看到刪除版本(無論是直接<@ .. @>ReflectedDefinition):

<@ myObj.Foo() @> ~> <@ someFunc(myObj, "Foo") @> 

FunScript類型提供程序的工作方式是它生成一些包含函數名稱的虛擬代碼,以便它可以生成相應的找到JavaScript。假設你有:

<@ win.Alert(arg) @> ~> <@ invokeFunction("alert", win, arg) @> 

要做到同樣的事情,你需要這樣定義一個函數invokeFunction,併產生相應的InvokeCode。然後,您可以在生成的報價單中查找致電invokeFunction的電話,並執行您需要在此處執行的任何特殊操作。你很難看到你到底想要做什麼,但這至少應該指向正確的方向。

+0

非常感謝您花時間解釋這一點。我沒有意識到** InvokeCode **定義非常重要。我只是試圖生成與類型提供程序的公共接口一樣深的類型,因此在我的示例中是愚蠢的代碼。根據這些信息,編寫一個類型提供程序對於我真正想要做的事情來說是矯枉過正的,這就是代碼生成界面。 –

相關問題