Я использую Visual Studio 2010 для написания простого приложения с графическим интерфейсом на C # /. NET, где я использую класс Logger
для записи информации трассировки / отладки в один файл из всех различных классов проекта.(См. Исходный код ниже.)
Конструктор каждого класса записывает запись в журнал, когда создается один из его типов объектов.Одним из этих классов является пользовательский компонент контроллера графического интерфейса (класс FileAttributesCtl
), который содержится в нескольких формах графического интерфейса, используемых программой.
Проблема, с которой я столкнулся, состоит в том, что созданы два файла журнала.около 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 года: Доступ к одноэлементному объекту из другого потока но у него нет ответов на мой вопрос.
Обновление
Дальнейшие исследования показывают, что VS2010 действительно создает экземпляр пользовательского компонента во время сборки, возможно, так, что онможет отобразить его в окне Designer.
Кроме того, действительно есть два отдельных потока, вызывающих конструктор Logger
(каждый из которых имеет свой ManagedThreadID
).
Использование инициализатора статического класса дляпостроить одиночный объект не работает;Я все еще получаю два файла журнала.
Разрешение
При ближайшем рассмотрении я замечаю, что пользовательский элемент управления создается дважды, и это показано в обоих файлах журнала.
Поэтому я думаю, что проблема полностью в том, что VS создает экземпляр пользовательского объекта управления до выполнения программы , что приводит к созданию первого файла журнала.Затем создается второй файл журнала после того, как программа начинает нормальное выполнение .
Таким образом, первый файл журнала является просто побочным эффектом процесса сборки и на самом деле не имеет ничего общего с несколькими потоками.выполнение во время нормальной работы программы.
Очевидное решение состоит в удалении всего кода побочного эффекта файла журнала из конструкторов компонентов.Или просто полностью игнорируйте первый лог-файл.