寻找与lambda表达式一起使用时Reflection.Emit的行为的说明

时间:2017-08-18 17:12:08

标签: c# .net lambda cil reflection.emit

具体来说,我正在尝试创建一个方法,该方法接受lambda表达式,然后在运行时将该表达式作为临时控制台应用程序的主方法旋转,以便允许将小部分代码作为单独的代码分离在运行时进程,所以我可以更好地隔离内存行为(我确实查看了应用程序域,但由于我的用例的某些限制,遇到了其他问题)。一个非常有限的分叉。

如果可以假设lambda表达式只包含局部变量,那么这是相对简单的,但我正在努力弄清楚我将要做多少(以及如何最好的方法是)如果表达式也使用非局部变量(即,存在于封闭范围内的变量,根据下面的注释。我无法想到更好的方式来表达短语&#34 ;一个不在本地范围内但可以访问的变量")。

据我所知,非局部变量意味着将在MSIL内生成某种字段加载指令。虽然我可以在辅助应用程序中复制所需的对象/字段,但如果我尝试通过MethodBody.GetILAsByteArray()按原样获取lambda表达式的MSIL,那么生成的代码(我相信)将包含字段加载指令的目标元数据表条目可能(很可能会)与控制台应用程序中通过Reflection.Emit创建的那些对象/字段的副本的元数据表条目不同。

更复杂的是关闭这个问题,我认为/如果我没记错的话,意味着lambda表达式主体中的任何非本地引用都会导致创建一个保存值的对象(副本?引用?I不记得了)。我可能不需要担心这一点,因为一旦它作为我的特定用例中的第二个应用程序被发出,它实际上不会成为lambda表达式吗?如果我刚刚获得方法体,我想我最终会回避通常的闭包处理?

最终我有两个问题:

一个。在我对整个过程如何运作的一般理解中,我是否缺少任何东西

B中。我是否必须在MSIL中只进行字段表引用,如果是这样,那么最实用的方法是什么呢?有没有办法让Reflection.Emit为我做这些调整?

当然,我很高兴听到是否有一些不那么令人沮丧的方式来完成我正在尝试做的事情,并对任何建议持开放态度。

1 个答案:

答案 0 :(得分:1)

在匿名方法/ lambda表达式之外访问局部变量会创建一个包含变量的闭包对象。假设您将lambda作为委托传递, Target 属性将包含委托的外部状态(类似于 DisplayClass )。除非您修改方法的CIL,否则您无法通过此类从远程进程获得实时通信,但您只需将其序列化并将其传递给远程进程即可。当然,如果委托取决于静态字段,那么您只需要分析方法来查找它们并将它们序列化(使用 System.Linq.Expressions 会很有用)。

现在,如果远程进程引用主程序集,它将在那里找到 DisplayClass ,但如果没有,你将不得不序列化它的类型并在另一侧构建它,挂钩它使用 AppDomain.TypeResolve 的方法。然后,您可以使用创建的类型反序列化对象。