我使用.net核心模板dotnet new typeprovider -n LemonadeProvider -lang F#创建了一个空白类型提供程序。该项目已建立,但是当我想更改一个Provide方法以在表达式中调用另一个这样的方法时:

let allEntities () = "dd"
let meth = ProvidedMethod("AllEntities", [], typeof<string>, invokeCode = (fun _ -> <@@ allEntities () @@>))
myType.AddMember(meth)

我尝试通过以下代码进行测试:

type Connection = LemonadeProvider.GenerativeProvider<"5">


[<Fact>]
let ``AllEntities simply works`` () =
    let obj = Connection()
    Assert.true(obj.AllEntities() = "dd")

我收到以下错误:

LemonadeProvider.Tests.fs(20,19): error FS3033: TypeProvider "LemonadeProviderImplementation+BasicGenerativeProvider" reports an error:: The design-time type 'LemonadeProviderImplementation+allEntities@96' utilized by a type provider was not found in the target reference assembly set '[tgt assembly Microsoft.VisualStudio.CodeCoverage.Shim, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly WitAi.Runtime, Version=1.0.0.0, Culture=neutral; tgt assembly xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c; tgt assembly xunit.assert, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c; tgt assembly xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c; tgt assembly xunit.execution.desktop, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c; tgt assembly System.ComponentModel.Annotations, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ComponentModel.EventBasedAsync, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Diagnostics.Contracts, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Dynamic.Runtime, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Linq.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Net.NetworkInformation, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Serialization.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Serialization.Primitives, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Serialization.Xml, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ServiceModel.Duplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ServiceModel.Http, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ServiceModel.NetTcp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ServiceModel.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ServiceModel.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Xml.XmlSerializer, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; tgt assembly System.Collections.Concurrent, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Collections, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Diagnostics.Debug, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Diagnostics.Tools, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Diagnostics.Tracing, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Globalization, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.IO, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Linq.Expressions, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Linq.Queryable, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Net.Primitives, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Net.Requests, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Net.WebHeaderCollection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.ObjectModel, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection.Emit, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection.Emit.ILGeneration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection.Emit.Lightweight, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Reflection.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Resources.ResourceManager, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Extensions, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Handles, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.InteropServices, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Runtime.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Security.Principal, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Text.Encoding, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Text.Encoding.Extensions, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Text.RegularExpressions, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Threading, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Threading.Tasks, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Threading.Tasks.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Threading.Timer, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Xml.ReaderWriter, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tgt assembly System.Xml.XDocument, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; tmp5A6]'. You may be referencing a profile which contains fewer types than those needed by the type provider you are using. [C:\git\LemonadeProvider.Tests.fsproj]

ProvideMethod简单地返回const值时,一切似乎都很好,而我没有收到错误:

let allEntities () = "dd"
let meth = ProvidedMethod("AllEntities", [], typeof<string>, invokeCode = (fun _ -> <@@ ("dd") @@>))
myType.AddMember(meth)

提供程序的整个代码如下所示:

[<TypeProvider>]
type BasicGenerativeProvider (config : TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces (config, assemblyReplacementMap=[("LemonadeProvider.DesignTime", "LemonadeProvider.Runtime")])

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

    // check we contain a copy of runtime files, and are not referencing the runtime DLL
    do assert (typeof<DataSource>.Assembly.GetName().Name = asm.GetName().Name)

    let createType typeName (auth: string, version: string) =

        let asm = ProvidedAssembly()
        let myType = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<obj>, isErased=false)

        let ctor = ProvidedConstructor([], invokeCode = fun args -> <@@ "My internal state" :> obj @@>)
        myType.AddMember(ctor)

        let ctor2 = ProvidedConstructor([ProvidedParameter("InnerState", typeof<string>)], invokeCode = fun args -> <@@ (%%(args.[1]):string) :> obj @@>)
        myType.AddMember(ctor2)
        let allEntities () = "dd"
        let meth = ProvidedMethod("AllEntities", [], typeof<string []>, invokeCode = (fun _ -> <@@ allEntities () @@>))
        myType.AddMember(meth)

        asm.AddTypes [ myType ]

        myType

    let myParamType =
        let t = ProvidedTypeDefinition(asm, ns, "GenerativeProvider", Some typeof<obj>, isErased=false)
        t.DefineStaticParameters( [ProvidedStaticParameter("AuthToken", typeof<string>)], fun typeName args -> createType typeName ("token", "version"))
        t
    do
        this.AddNamespace(ns, [myParamType])

最佳答案

我的观察:

  • 编译测试时,LemonadeProvider.DesignTime dll将参与fsc管道(在实际编译之前),以根据您提供的createType定义生成类型。
  • 类型是从LemonadeProvider.DesignTime在单独的程序集中生成的(似乎是匿名的),它与LemonadeProvider.Runtime.dll一起包含在测试源的实际编译过程中。请注意,此步骤似乎不再包括LemonadeProvider.DesignTime。首先,我认为LemonadeProvider.Runtime.dll包含生成的类型,但是在ilspy中检查后,我没有找到任何类型。
  • 实际的源代码编译不包括
  • LemonadeProvider.DesignTime。这意味着此处定义的任何类型(如模块助手的定义)将不可用。但是,当您编写以下命令时:let allEntities() = "dd"-这将在LemonadeProvider.DesignTime中生成一个类。在我的情况下是:

  • f# - TypeProvider无法从Expression添加方法-LMLPHP

    但是这个班是not reachable
  • 行:

  • let meth = ProvidedMethod("AllEntities", [], typeof<string>, invokeCode = (fun _ -> <@@ allEntities() @@>))
    

    AST的报价单类似于:
    f# - TypeProvider无法从Expression添加方法-LMLPHP
    -请注意,类型是在AST内部捕获的。因此,当在没有DesignTime.dll的上下文中发生反序列化报价时,您会看到编译错误。
  • 对于代码:

  • let allEntities = "dd"
    let allEntitiesQuote = <@@ allEntities @@>
    

    我们有下一个AST:ValueWithName(“dd”,allEntities)-因此没有对类型的引用。
  • 要在引号内包含函数-使用DataSource类。它也在Runtime dll中定义,因此将找到相应的生成函数类型。
    在Runtime.fsproj中,Runtime.fs:

  • type DataSource(filename:string) =
        member this.FileName = filename
        static member allEntities() = "dd"
    

    这对我有用。您也可以在“实用工具”模块中拥有allEntities,但删除内部关键字。
  • 如果您仍然希望在DesignTime dll中具有函数定义,则假定您需要以引号的形式对其进行组织,并为其提供Provided *方法。
  • 09-11 15:56