如何以编程方式检测副作用(编译时间或运行时间)?
我有一个关于缓存的想法,我已经开始实现了:
记忆函数并将返回与Velocity中的函数签名的散列一起存储。 使用PostSharp ,我想检查缓存并返回返回值的重新水合表示,而不是再次调用该函数。 我想使用属性来控制这种行为。
不幸的是,如果他们爱上了性能提升并开始使用缓存属性(包括一些带有副作 当memoization库怀疑某个函数可能会导致副作用时,我想发出一个编译器警告。
如何判断代码可能会导致使用CodeDom或Reflection产生副作用?
无论是在实践中还是在理论上,这都是一个极其困难的问题。 我们正在考虑如何预防或隔离精确场景的副作用 – 记忆, 自动并行化等等 – 但这很困难,而且我们仍然远不是C#的可行解决方案。 所以,没有承诺。 (如果你真的想要消除副作用,请考虑切换到Haskell。)
不幸的是,即使奇迹发生了,你找到了一种方法来防止有副作用的方法的记忆,你仍然有一些大问题。 考虑以下:
1)如果你记住一个本身调用memoized函数的函数怎么办? 这是一个很好的情况,对吗? 您希望能够撰写记忆function。 但是memoization有副作用:它将数据添加到缓存! 所以你马上就会遇到一个元问题:你想要驯服副作用,但只有“坏”的副作用。 你想要鼓励的“好”,你想要阻止的坏的,并且很难区分它们。
2)你对exception做什么? 你能记住引发exception的方法吗? 如果是这样,它是否总是抛出相同的exception,或者每次都抛出一个新的exception? 如果是前者,你打算怎么做? 如果是后者,现在你有一个memoized函数,它在两个不同的调用上有两个不同的结果,因为抛出了两个不同的exception。 例外可被视为副作用; 很难驯服exception。
3)对于没有副作用但仍然不纯的方法的方法,你打算做什么? 假设您有一个GetCurrentTime()方法。 这没有副作用; 电话没有任何变异。 但这仍然不是备忘录的候选者,因为任何两个调用都需要产生不同的结果。 您不需要副作用检测器,需要纯度检测器。
我认为你最好的办法是通过教育和代码审查解决人类问题,而不是试图解决棘手的技术问题。
简单来说,你无法使用CodeDom或Reflection。
要准确确定方法是否会产生副作用,您必须了解它正在采取的操作。 对于.Net来说,这意味着打开IL并以某种方式对其进行交互。
Reflection或CodeDom都没有为您提供此function。
- CodeDom是一种在应用程序中生成代码的方法,只有非常有限的检查function。 它基本上局限于各种解析版本所理解的语言子集。
- 反思的优势在于它能够检查元数据而不是方法体的基础IL。 MetaData只能为您提供一组非常有限的信息,包括哪些内容和不起副作用。
reflection本身不会这样做,因为元数据没有任何这样的属性。
CodeDom可能不够强大,无法检查所有IL指令。
因此,您必须使用reflectionAPI的非常低级的部分,它们可以让您获得包含每种方法的原始IL的byte[]
,并对其进行分析。 所以它原则上是可能的,但并不容易。
您必须分析所有指令并观察它们具有什么效果,以及这些效果是否会在某个重要范围之外生存(例如,它们是否会修改可能通过返回值或out
参数泄漏的对象字段,或者他们只修改保证在方法外无法访问的瞬态对象吗?)。
听起来很复杂!
- 更快地从Lucene Query获取不同值的方法
- 带有公钥的RSA C#加密用于PHP openssl_private_decrypt():Chilkat,BouncyCastle,RSACryptoServiceProvider
- 将类转换为动态并添加属性
- 启动时Windows 10 Universal app屏幕尺寸无法正常工作
- 更新Entity Framework 4.1中的外键实体
- 有没有关于编写软件安装程序的权威文档?
- C#属性用法:仅允许具有特定数据类型的属性上的属性
- 如何在Visual Studio 2017项目(新的.csproj文件格式)中设置`OutputPath`属性,而不会使目标框架混乱已解析的路径?
- 什么是GC孔?