我一直在使用来自FSharp的XmlProvider。生成类型对应于XML片段的数据,我将其存储在正在构建的f#项目源目录中的文件中。
我用文件的路径参数化XmlProvider。然后将此代码编译成DLL。
如果我然后从另一个无法从源目录读取的f#项目引用该程序集的编译DLL,那么在编译时间为该项目,我得到错误FS3033 '无法从'config_schema.xml'读取示例XML:无法找到(路径)'。
为什么会这样?我的理解是,在编译之后,与XML示例相对应的类型是一个标准的完全成熟的类型,这就是编译后的DLL中应该结束的类型。为什么类型的使用者(第二个项目中的代码)仍然需要引用示例来编译?
这很微妙。当您将使用擦除类型提供程序(如XmlProvider
或JsonProvider
)的代码编译到DLL中时,编译器实际上并不存储生成的类型。这意味着当您从另一个库引用DLL时,编译器将再次触发类型提供程序—即使最终用户代码(库的用户)实际上并没有使用类型提供程序。
这意味着类型提供程序需要能够访问示例,即使在编译了库并将其分发给用户之后也是如此。
您可以使用相对路径并将示例复制到您的库中,但这不是很优雅。我们实际上在f#数据工具箱中有完全相同的问题,这是一个在封面下使用JsonProvider
的库。
f# Data有一个特殊的选项。您可以在编译DLL时将示例作为资源嵌入-这样,类型提供程序将首先查找嵌入的资源(在您分发库之后工作),如果它不在那里,它将查找本地文件(在编译库时需要)。
看看f#数据工具箱是怎么做的:
type Response = JsonProvider<"json/bearer_token.json",
EmbeddedResource="FSharp.Data.Toolbox.Twitter,bearer_token.json">
在项目文件中设置嵌入的资源:
<EmbeddedResource Include="json/bearer_token.json">
<Link>json/bearer_token.json</Link>
</EmbeddedResource>