MethodNotFound、单例类和“优化代码”
我正在用 C# 编写一个 .net 紧凑框架应用程序。它在开发环境中工作正常,但是当以发布模式构建并自行运行时,它会抛出 MethodNotFound 异常。我撒了一堆调试日志代码来找出它的问题所在,并将其缩小到一个大的 Init() 函数。这又调用了几个单例类上的方法,这些方法的实现如下:
private SingletonClass() {}
private static readonly SingletonClass _instance = new SingletonClass();
public static SingletonClass Instance
{
get
{
return _instance;
}
}
我注意到的一件事是,来自单例类中构造函数的调试条目将在 Init() 函数中的第一个条目之前被记录。看起来运行时引擎在实际开始运行我的代码之前正在幕后做一些事情。
一旦我在这些单例类中拥有“足够的”调试代码,它就不会抛出 MethodNotFound 异常,并且程序将运行得很好。我说“足够”是因为我可以注释掉调试代码并获取 MethodNotFound。当我再次取消评论时,它起作用了。
奇怪的是,当未抛出异常时,调试日志条目将按照我的代码调用它们的顺序排列。这几乎就像运行时引擎没有像抛出 MethodNotFound 时那样执行“幕后”操作。
我尝试清除具有单例类的项目上的“优化代码”选项,它似乎已经解决了问题。 (我一开始尝试过这个,但经过惨痛的教训,UI 项目上的项目选项不会影响业务逻辑项目。)
我发现的几篇关于 MethodNotFound 的帖子谈到了缺少 DLL、错误的 DLL 版本或内存不足。
我确实找到了一篇文章,讨论编译器如何处理单例类中使用的静态内容。
http://www.yoda.arachsys.com/csharp/singleton.html
我认为这与我遇到的问题有关,但最终我必须清除“优化代码”才能使其正常工作。
所以我的问题是到底发生了什么事?它正在发挥作用,因此目前这是一个学术问题。希望这能减轻其他人的头痛。
I'm writing a .net compact framework app in c#. It was working fine in the development environment but when built in release mode and run by itself, it was throwing MethodNotFound exceptions. I sprinkled a bunch of debug logging code to find out where it was breaking and narrowed it down to a big Init() function. This in turn calls methods on a several singleton classes which are implemented like this:
private SingletonClass() {}
private static readonly SingletonClass _instance = new SingletonClass();
public static SingletonClass Instance
{
get
{
return _instance;
}
}
One thing I noticed is that the debug entry from the constuctor in the singleton class would get logged before the first entry in the Init() function. It looks like the runtime engine was doing something under the hood before it actually starting running my code.
Once I had "enough" debug code in those singleton classes, it wouldn't throw the MethodNotFound exception and the program would run just fine. I say "enough" because I could comment out the debug code and get MethodNotFound. When I un-commented it again, it worked.
The weird part is that when the exception was not thrown, the debug log entries would be in the order that my code called them. It was almost like the runtime engine wasn't doing its "under the hood" stuff that it did when MethodNotFound was thrown.
I tried clearing the "Optimize code" option on the project that had the singleton classes and it seems to have solved the problem. (I tried this at first but learned the hard way that project options on the UI project don't effect the business logic project.)
The few posts about MethodNotFound that I did find talked about missing DLLs, wrong DLL versions or running low on memory.
I did find a post that talks about how the compiler deals with static stuff used in singleton classes.
http://www.yoda.arachsys.com/csharp/singleton.html
I think it's related to the problem I'm having but in the end I had to clear "optimize code" to get it to work.
So my question is what the heck is going on? It's working so this is an academic question at this point. Hopefully this will save someone else the headache.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您是否在代码中的任何位置使用反射来遍历调用堆栈? (搜索 StackFrame 或 StackTrace 类)
优化代码时通常会内联小函数,这意味着特定方法可能会从发布版本的调用堆栈中完全消失。如果您希望该方法出现在调用堆栈中,您可能会看到内联。
当您将调试代码添加到一个小函数时,我猜测 JIT 会停止将其判断为可内联函数,因此该方法会返回到调用堆栈中,您的问题就会消失。
您可以使用 CompilerServices 将方法标记为不可内联.MethodImpl 属性。尝试将其应用于通过添加调试代码已“修复”的函数之一。
另请参阅http://blogs.msdn.com/davidnotario/archive/2004/11/01/250398.aspx
Are you using reflection anywhere in your code to walk the call stack? (search for StackFrame or StackTrace classes)
Small functions are often inlined when code is optimised, which means particular methods may disappear entirely from the call stack in a release build. If you're expecting that method to be there in the call stack, you may be seeing inlining.
When you add debugging code to a small function, I'm guessing that the JIT stops judging it as an inlineable function, and so the method goes back into the call stack and your problem disappears.
You can mark a method as not-inlinable with the CompilerServices.MethodImpl attribute. try applying this to one of your functions which was 'fixed' by adding debug code.
See also http://blogs.msdn.com/davidnotario/archive/2004/11/01/250398.aspx