3
votes

F# 4.0 introduced the ability to provide static parameters to provided methods (see http://blogs.msdn.com/b/fsharpteam/archive/2014/11/12/announcing-a-preview-of-f-4-0-and-the-visual-f-tools-in-vs-2015.aspx)

I want the return type of my provided method to depend upon the static parameters the user supplies.

I need to define the return type outside of the DefineStaticParameters callback in order that I can pass it to this.AddNamespace but unfortunately this means that AddMethod gets called multiple times and I end up with a bunch of unwanted overloads. If I move the creation of returnType inside the DefineStaticParameters callback then I cannot pass it to AddNamespace and the type provider no longer functions.

How do I resolve this conundrum?

Example code:

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

    let ns = "Acme"
    let asm = Assembly.GetExecutingAssembly()

    let t = ProvidedTypeDefinition(asm, ns, "MyStaticClass", Some typeof<obj>, IsErased = true)    
    let returnType = ProviderImplementation.ProvidedTypes.ProvidedTypeDefinition(asm, ns, "MyReturnType", Some typeof<obj>, IsErased = true, HideObjectMethods = true)

    let myStaticMethod =
      let m = ProvidedMethod("SomeStaticMethod", [], typeof<obj>, IsStaticMethod = true)

      m.DefineStaticParameters(staticParams, fun nm args ->

        let providedMethod = ... // Generate a method for the return type depending on the args
        returnType.AddMember(providedMethod) // PROBLEM: This gets called multiple times and adds unwanted overloads to my returnType

        let m2 =
          let myParam = ProvidedParameter("foo", typeof<int>)
          ProvidedMethod(nm, [myParam], returnType, IsStaticMethod = true)

        m2.InvokeCode <- fun args3 ->
          <@@
            // invoke code goes here
          @@>

        t.AddMember(m2)
        m2
        )
      m

    do
      t.AddMember(myStaticMethod)
      this.AddNamespace(ns, [t;returnType])

[<assembly:TypeProviderAssembly>]
do ()
1

1 Answers

1
votes

If you really need to add new types to the namespace each time a different static parameter is used, then I think the only way to do that would be to store the information you need in a cache and trigger the Invalidate event when you need to add a new type to the namespace, repopulating all of the types from your cache afterwards.