我试图解释有关传递依赖关系的Release和Debug配置之间奇怪的F#编译器行为。我将在这里使用Newtonsoft.Json
包作为基本依赖项,因为这是我设法找到问题所能达到的最远的,并且它使示例不那么抽象。
让我们创建一个名为SerializerProject
的库项目,通过paket引用Newtonsoft.Json
。在这个项目中只有一个模块:
module Serializer =
open System.IO
open System.Text
open Newtonsoft.Json
type OptionConverter() =
inherit JsonConverter()
(* only the signature is important, the implementation
and other methods are not interesting *)
override x.WriteJson(writer: JsonWriter, value: obj, serializer: JsonSerializer) =
(* ... *)
let fromJson<'a> (bytes: byte []): 'a =
let s = Encoding.UTF8.GetString(bytes)
use sr = new StringReader(s)
use jr = new JsonTextReader(sr)
let serializer = JsonSerializer()
serializer.Converters.Add(OptionConverter())
serializer.Deserialize<'a>(jr)
现在让我们在同一个解决方案中创建第二个项目,并通过项目参考引用SerializerProject
。我想在我的新项目中使用fromJson
,这就是我首先引用SerializerProject
的原因。
module MyModule =
open Serializer
(* This is here just so we reference the fromJson function *)
let deserializer bytes = fromJson bytes
这是重现行为的最小例子。
现在,当我在Debug配置中构建解决方案时,一切都编译并正常工作。但是当我切换到Release时,编译在第二个项目中失败,在deserializer
定义中的MyModule中。确切的错误信息是:
通过&#39; Newtonsoft.Json.JsonWriter&#39;引用的类型在未引用的程序集中定义。您必须添加对程序集的引用&#39; Newtonsoft.Json&#39;
我使用Visual Studio 2015 Update 3,F#工具(fsc,fsi)显示版本14.0.23413.0。
这是有道理的,因为它正在阅读SerializerProject
的元数据,并发现公开OptionConverter
类型在其公开JsonWriter
上泄漏了WriteJson
类型方法(以及其他类型和其他方法,但首先遇到这个方法),但是让我想知道为什么它在调试模式下有效并且只是Release模式中的问题。
Newtonsoft.Json
中定义的类型真正泄漏到第二个项目中时,为什么这不是Debug构建中的问题?正如评论中所建议的那样,我尝试引用Newtonsoft.Json
并使用ILSpy反编译第二个程序集,以查看编译器优化是否启用内联是否应该归咎于此,但即使在Release配置中,第二个程序集如下所示: / p>
call !!0 [SerializerProject]Serializer::fromJson<!a>(uint8[])
fromJson
函数尚未内联直接显示JsonWriter
类型,因此似乎有更微妙的内容。
这不是阻塞问题,我只是将转换器类型设为私有,因为我不想从外面使用它们,但我想深入挖掘F#编译器内部工作原理