我需要缓存来自同一基类的几个不同类所做的繁重计算的结果。我正在通过子类名进行运行时缓存。现在我需要将结果存储在磁盘/数据库上以避免在重新启动应用程序时进行长时间重新计算,但如果我更改Calculate()
中的代码,我需要使缓存无效。
type BaseCalculator() =
let output = ConcurrentDictionary<string, Series<DateTime, float>>() // has public getter, the output is cached by the caller of Calculate() method
abstract Calculate: unit->unit
type FirstCalculator() =
inherit BaseCalculator()
override this.Calculate() = ... do heavy work here ...
从this问题和答案我了解到我可以在计算方法上使用[<ReflectedDefinition>]
。但我以前从未使用过引文。
问题是:
[<ReflectedDefinition>]
应用于抽象方法,如果我在C#中覆盖方法,它会工作,但是从F#runner调用方法吗? (我使用反射来加载文件夹中所有dll中基类的所有实现)stable
和WIP
计算器分隔为单独的程序集,则可以使用此功能,但首选更多粒度。答案 0 :(得分:3)
我可以使用引号的哈希码来唯一地标识方法的主体,或者引用内部有一些guid或时间戳吗?
我认为这会奏效。查看FsPickler(MBrace用于序列化引用)。我认为它也可以给你一个报价的哈希。但请记住,代码的其他部分可能会更改(例如,另一种类型的其他方法)。
可以
ReflectedDefinition
应用于抽象方法,如果我在C#中覆盖方法,它会工作,但是从F#runner调用方法吗?
不,该属性仅适用于使用F#编译器编译的F#方法。
是否有其他简单可靠的方法可以自动检测程序集中的代码更改,而无需引用?
我不确定。您可以使用GetMethodBody
method和.NET反射来获取IL,但这只会给您直接的身体 - 不包括例如lambda函数,因此在其他地方发生的变化不容易被发现。
一种可能更好用的完全不同的方法是将FSX文件中的计算保持为纯文本,并使用F# Compiler Service动态编译它们。然后你可以只对每个FSX文件的源进行散列(基于每个计算)。
答案 1 :(得分:0)
我发现Mono.Cecil非常容易使用,有了它我可以哈希所有类型的成员体,包括基类型。
This SO question作为起点非常有用。