在 clr 调用堆栈中看到接口是否正常?

Is it normal to see an interface in a clr callstack?

我有一个 asp.net 应用程序崩溃了。在包含此调用堆栈的 windows 事件日志中有一个条目:

 Exception type: EntryPointNotFoundException 
    Exception message: Entry point was not found.
   at ***.Interfaces.Portal.Repository.ILookup.get_LookupDataCollection()
   at ***.Portal.Repository.Lookup.GetLookUpValue(ILookup lookup, Int32 index)
   at ***.Portal.Repository.Lookup.GetLookUpValue(ILookup lookup)
   at ***.HttpModules.RuntimeHttpModule.SetPageUrlInfoInContext(PageUrlInfo pinfo)
   at ***PortalRuntime.HttpModules.RuntimeHttpModule.BeginRequest(Object sender, EventArgs e)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

这只发生在客户机器上,我无法在本地重现。正如您在顶部看到的那样,有一个接口(ILookup,它实际上是一个接口,而不是 class)。

我构建了一个类似的示例(通过接口调用的方法)。 Visual Studio 2015 年足够聪明,可以证明这一点:

ConsoleApplication2.exe!ConsoleApplication2.Lookup.GetLookupId(ConsoleApplication2.ILookup lookup) Line 37  C#

但是您仍然可以看到实现该方法的 class。我还使用 windbg 附加到我的示例,并在应用程序位于通过接口调用的方法中的断点时打印堆栈:接口不在堆栈上。

这是我的问题:

我可以稍微解释一下你为什么会看到这个,这对解决你的问题一点帮助都没有。我也不太了解 CLR 将接口方法绑定到它们的实现的方式,这太疯狂了 micro-optimized.

问题是抖动必须为包含接口方法调用的方法生成代码。但它还不能知道对象引用的身份。在代码实际执行之前,这并不知道 100% 准确。所以它所做的是分配一个 stub,一个目标方法的占位符。并为该存根生成一条 CALL 指令。该存根方法的实际名称无关紧要,当真正的目标方法被解析时,它将再次消失。

存根本身生成对 CLR 的调用以解析目标方法,现在知道对象引用的真实身份以及需要执行哪个具体实现方法。并修补机器代码,以便替换 CALL 地址。因此,在 下一次 方法执行时,您无需支付方法绑定的代价,并且调用以最大可能的扭曲速度运行。

如前所述,存根的名称并不重要,因为它是临时的。为其指定接口方法的名称非常有助于诊断 MissingMethodException。好主意。

真正的问题是加载的程序集不是您构建代码所用的程序集。可能是您忘记重新部署的旧版本。或者您只是在更改界面时忘记重建它,因为它不是解决方案的一部分。所以它没有接口方法的实现,当存根执行时,CLR 很晚才发现这一点。所以你在调用堆栈上看到存根方法名称。