使用F#引用来检测代码更改

时间:2015-06-30 14:34:36

标签: c# .net f#

我需要缓存来自同一基类的几个不同类所做的繁重计算的结果。我正在通过子类名进行运行时缓存。现在我需要将结果存储在磁盘/数据库上以避免在重新启动应用程序时进行长时间重新计算,但如果我更改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>]。但我以前从未使用过引文。

问题是:

  • 我是否可以使用引号的哈希码来唯一标识方法的主体,或者引用内部有一些guid或时间戳?
  • 可以[<ReflectedDefinition>]应用于抽象方法,如果我在C#中覆盖方法,它会工作,但是从F#runner调用方法吗? (我使用反射来加载文件夹中所有dll中基类的所有实现)
  • 是否有其他简单可靠的方法可以自动检测程序集中的代码更改,而无需引用?使用程序集文件(dll)的上次修改时间可能有效,但程序集中的任何更改都将使程序集中的所有计算器无效。如果我将stableWIP计算器分隔为单独的程序集,则可以使用此功能,但首选更多粒度。

2 个答案:

答案 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作为起点非常有用。