【发布时间】:2010-08-18 06:31:30
【问题描述】:
我正在使用 Visual Studio 2010 编写一个简单的 C#/.NET GUI 应用程序,其中我使用 Logger 类将跟踪/调试信息从项目的所有各种类中写入单个文件。 (见下面的源代码。)
当实例化其对象类型之一时,每个类的构造函数都会将条目写入日志。其中一个类是自定义 GUI 控制器组件(FileAttributesCtl 类),它包含在程序使用的几个 GUI 表单中。
我遇到的问题是创建了两个日志文件,相隔约 200 毫秒。第一个日志文件(仅)包含一条消息,表明已构建 FileAttributesCtl 对象,第二个日志文件包含写入(假定)共享日志文件输出流的所有其他消息。所以每次我执行我的项目代码时,我都会得到两个日志文件。
更奇怪的是,每次我重建我的项目 (F6) 时,都会为 FileAttributesCtl 对象创建一个日志文件,表明这种类型的控制对象实际上是在构建过程中实例化的。
这显然与线程有关。如果日志文件不是唯一命名的(即,如果我没有将唯一的日期/时间字符串附加到文件名),我会得到一个异常,表明多个进程(实际上是 VS2010 进程本身)当前正在使用文件。
所以我的问题是:我如何让单例对象实际上是一个对象?
第二个问题是:为什么 VS2010 会这样?
//----------------------------------------
// Logger.cs
class Logger
{
// Singleton object
private static Logger s_logger =
new Logger("C:/Temp/foo.log");
public static Logger Log
{
get { return s_logger; }
}
private TextWriter m_out;
private Logger(string fname)
{
// Add a date/time suffix to the filename
fname = ...;
// Open/create the logging output file
m_out = new StreamWriter(
new FileStream(fname, FileMode.Create, FileAccess.Write,
FileShare.Read));
m_out.WriteLine(DateTime.Now.ToString(
"'$ 'yyyy-MM-dd' 'HH:mm:ss.fff"));
}
...
}
//----------------------------------------
// FileAttributesCtl.cs
public partial class FileAttributesCtl: UserControl
{
private Logger m_log = Logger.Log;
public FileAttributesCtl()
{
m_log.WriteLine("FileAttributesCtl()"); //Written to first logfile
InitializeComponent();
}
...
}
//----------------------------------------
// FileCopyForm.cs
public partial class FileCopyForm: Form
{
private Logger m_log = Logger.Log;
public FileCopyForm()
{
// Setup
m_log.WriteLine("FileCopyForm()"); //Written to second logfile
// Initialize the GUI form
m_log.WriteLine("FileCopyGui.InitializeComponent()");
InitializeComponent();
...
}
...
}
注意:这与 2009 年 12 月的一个问题非常相似:
Access to singleton object from another thread
但它没有我的问题的答案。
更新
进一步调查表明,VS2010 确实在构建过程中实例化了自定义组件,可能是为了在设计器窗口中呈现它。
另外,确实有两个单独的线程调用Logger 构造函数(每个线程都有不同的ManagedThreadID)。
使用静态类初始化器构造单例对象不起作用;我仍然得到两个日志文件。
分辨率
经过仔细检查,我注意到自定义控件被实例化了两次,并且在两个日志文件中都显示了这一点。
因此,我认为问题完全在于 VS 在执行程序之前实例化了自定义控件对象,这会导致创建第一个日志文件。然后在程序开始正常执行后创建第二个日志文件。
因此,第一个日志文件只是构建过程的副作用,与正常程序操作期间执行的多个线程没有任何关系。
显而易见的解决方案是从组件构造函数中删除所有日志文件副作用代码。或者干脆完全忽略第一个日志文件。
【问题讨论】:
-
你最好下载 log4net 来完成这项工作:)
-
有谁知道
log4net是否可以解决这个问题? -
我不知道免疫但从他们的常见问题解答... log4net 线程安全吗?是的,log4net 是线程安全的。
标签: c# .net multithreading visual-studio-2010 singleton