下了個c#實現的輕量級IoC開源項目,可是在本地使用時發現一運行就捕捉到“類型初始值設定項引發異常”的異常信息,調試幾次還是不能確定到底什么地方出了問題。印象中好像碰到過這種異常,初步估計是某個靜態類初始化不成功引起的,但是不能肯定。
無奈打開ILSpy查看源碼,發現靜態初始化的地方非常多,而且代碼看上去層層嵌套,類名繁多,一行一行跟上去很容易繞暈。折騰好久未果,無奈google一下,發現早就有人和我碰到一樣的問題,一看投票最多的正確解決方法差點沒把自己搞瘋:項目中直接添加log4net.dll引用即可。
經試驗,果然。
啊啊啊啊啊啊啊啊啊啊啊啊啊…
原來是log4net,竟然又是log4net。
根據個人經驗,很多開源項目都使用了log4net用來記錄日志,比如在使用ibatis.net、postsharp、fastdfs的c#客戶端和memcached的c#實現的某客戶端的時候我都碰到過這個問題。
下次碰到相同的問題能迅速查找到原因嗎?能不再浪費時間嗎?還能做一些更有價值的事情嗎?
或者直接問是不是缺少log4net引用?kao,天曉得。
附:參考NLog的GetCurrentClassLogger()方法封裝一個日志類
項目中使用NLog記錄日志,經常在不同的服務(類庫)中引用NLog.dll,然后需要按照日期和類名(和配置相關,這里略)記錄一些日志,所以調用的時候通常都這么寫:
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
這樣做一次兩次三次當然都不會有問題,但是如果解決方案中類庫較多,老是要引用dll文件同時要記錄日志就在該類中寫上面一行代碼就會覺得不甚其煩了,所以你肯定想到要封裝一下簡化調用方式。
查看LogManager.GetCurrentClassLogger()它的源碼,我們看到它是這樣實現的:

LogManager.GetCurrentClassLogger
代碼很簡單,就是通過堆棧技術獲取到某一方法的調用者的類名,實現按照類名記錄日志的方法,這個和log4net中的實現方式是非常相似的。這樣我們自己可以封裝一個公共Logger類,通過靜態方法實現NLog中的多數常見的記錄日志的方法,下面給出一個記錄錯誤日志的簡單示例方法:

Logger
實際上這個實現中的logger還可以通過它的Name緩存,不需要每次都寫:
var stackFrame = new StackFrame(1, false); var logger = LogManager.GetLogger(stackFrame.GetMethod().DeclaringType.FullName);
畢竟反射是很耗性能的。
通常這個Logger類會封裝到公共類庫下,以后使用直接引用公共類庫項目,記錄日志直接Logger.Error形式地調用,大家自然happy了。
關於異常處理,據博客園牛人辰的這一篇所述,捕獲異常跟蹤到行微軟做的很不到位,作為不明真相的群眾之一,我覺得還是記錄一下將來要是碰到了快速解決也好。
參考:http://msdn.microsoft.com/zh-cn/library/33k1wxtt(v=vs.95).aspx
http://www.cnblogs.com/zc22/archive/2009/12/25/1631773.html
補充一則:理解組件和服務的區別
下面的文字來自Martin Fowler的文章Inversion of Control Containers and the Dependency Injection pattern的部分片段(Components and Services),自己參考后稍帶翻譯一小段並寫了一點自己的理解。
原文:
Components and Services
The topic of wiring elements together drags me almost immediately into the knotty terminology problems that surround the terms service and component. You find long and contradictory articles on the definition of these things with ease. For my purposes here are my current uses of these overloaded terms.
I use component to mean a glob of software that's intended to be used, without change, by an application that is out of the control of the writers of the component. By 'without change' I mean that the using application doesn't change the source code of the components, although they may alter the component's behavior by extending it in ways allowed by the component writers.
A service is similar to a component in that it's used by foreign applications. The main difference is that I expect a component to be used locally (think jar file, assembly, dll, or a source import). A service will be used remotely through some remote interface, either synchronous or asynchronous (eg web service, messaging system, RPC, or socket.)
I mostly use service in this article, but much of the same logic can be applied to local components too. Indeed often you need some kind of local component framework to easily access a remote service. But writing "component or service" is tiring to read and write, and services are much more fashionable at the moment.
組件和服務的異同
如何區分“服務”(service)和“組件”(component)?
所謂“組件”是指這樣一個軟件單元:它將被作者無法控制的其他應用程序使用,但后者不能對組件進行修改。也就是說,使用一個組件的應用程序不能修改組件的源代碼,但可以通過作者預留的某種途徑對其進行擴展,以改變組件的行為。
服務和組件有某種相似之處:它們都將被外部的應用程序使用。
在我(這里的我不是指樓豬,是Martin Fowler大大,樓豬注)看來,兩者之間最大的差異在於:組件是在本地使用的(例如JAR 文件、程序集、DLL、或者源碼導入);而服務是要通過——同步或異步的——遠程接口來遠程使用的(例如web service、消息系統、RPC,或者socket)。