我已经编写了我的第一个MVVM应用程序。当我关闭应用程序时,我常常因ObjectDisposedException而导致崩溃。在应用程序窗口消失后,应用程序即会崩溃。
获取堆栈跟踪很困难(see my other question),但最后我做了,发现我的堆栈跟踪完全包含在C#库中(kernel32!BaseThreadStart,mscorwks!Thread,mscorwks!WKS等)。
此外,这次崩溃是不一致的。在我上次结账和重建之后,它停止了一段时间。然后它又回来了。一旦它开始发生,它就会一直发生,即使我“清理”并重建。但擦拭和结账有时会让它停止一段时间。
我认为发生了什么:
我认为GarbageCollector在处理我的ViewModel时做的很有趣。我的ViewModelBase类析构函数在调用析构函数时有一个WriteLine来记录,而我的4个ViewModel中只有2或3个被处理掉了,它似乎根据结帐而有所不同(例如,当我在我的运行时,我看到一直在重复顺序,但我的同事看到不同的序列,不同的对象被处置)。
由于堆栈跟踪没有我的代码调用,我认为这意味着它不是我的代码调用被处置对象的方法。所以这让我觉得CLR很蠢。
这有意义吗?有什么方法可以让GC保持一致吗?这是红鲱鱼吗?
其他可能有用的细节:
我的所有Views和ViewModel都是在App.xaml.cs文件的Application的Startup事件处理程序中创建的。同一个处理程序将ViewModels分配给DataContexts。我不确定这是否是正确的MVVM实践(正如我所说的,我的第一个MVVM应用程序),但我不明白为什么它会导致不良行为。
如有必要,我可以粘贴代码。
答案 0 :(得分:13)
答案 1 :(得分:4)
您的应用程序抛出异常,因为当您的主应用程序退出时,您对ViewModel销毁的日志记录操作尚未完成。
您会发现,为了执行实际的文件编写,会生成子进程。如果在主应用程序退出时尚未完成,那么您将收到错误。
如果您要执行此类操作,那么您需要主应用程序等待一段时间才能完成任何子进程/线程池线程等。
如果您希望确保可以记录应用程序关闭期间发生的事件,那么我建议您将日志记录过程(实际写入日志文件)作为发布消息的单独主线程运行。这样,您的应用程序可以在您的日志记录过程完成写入磁盘之前关闭。
答案 2 :(得分:2)
我认为GarbageCollector在处理我的ViewModel时做的很有趣。我的ViewModelBase类析构函数有一个WriteLine,用于在调用析构函数时记录
这可能是那里的问题。你根本不应该使用终结器,除非你真的有充分的理由这样做,并且记录东西绝对不是其中之一。
您必须了解终结器不能以可预测的顺序运行。 GC可以按照它想要的顺序调用终结器,这可能解释了为什么你会得到看似随机的异常行为。