0

我已经实现了一个基本的日志记录类,当我尝试创建它的新实例时,我得到了以下异常。

该进程无法访问文件“C:\Users\carl\Desktop\My Projects\TCV2\CallPotential.UI\bin\Debug\application.log”,因为它正被另一个进程使用。

这是记录器类的代码。

using System;
using System.IO;
using System.Reflection;

namespace CallPotential.Utilities
{
    public class Logger : IDisposable
    {
        /// <summary>
        /// Used to write output to the log file.
        /// </summary>
        private StreamWriter _stream;

        /// <summary>
        /// The absolute path to the log files location.
        /// </summary>
        public String LogFileName
        {
            get
            {
                // get the directory where our main assembly is located.
                Assembly assembly = Assembly.GetExecutingAssembly();
                String directoryName = Path.GetDirectoryName(assembly.Location);
                return Path.Combine(directoryName, "application.log");
            }
        }

        /// <summary>
        /// Creates a new instance of the Logger class
        /// </summary>        
        public Logger()
        {         
           _stream = new StreamWriter(LogFileName);         
        }

        /// <summary>
        /// Writes a message out to the application log file.
        /// </summary>
        /// <param name="message">The message to write to the log file.</param>
        public void Write(String message)
        {
            _stream.WriteLine(message);
            _stream.Flush();
            _stream.Close();
        }

        /// <summary>
        /// Writes a message including the applications state to the log file.
        /// </summary>
        /// <param name="state">The application state at the time of the logged message.</param>
        /// <param name="message">The message to be written to the log file.</param>
        public void Write(AppState state, String message)
        {
            Write(String.Format("{0}\r\n\t{1}", state, message));
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_stream != null)
                {
                    _stream.Dispose();
                    _stream = null;
                }
            }
        }
        ~Logger()
        {
            Dispose(false);
        }
    }
}

请注意原因,但它会在构造函数中引发异常。任何帮助解决这个问题将不胜感激。

4

5 回答 5

3

基本问题是您打开了一个流,这意味着您只能访问日志记录类的一个实例,除非您进行一些更改。

您可以进行的各种更改包括:

1) 确保每个实例生成自己的日志文件名。

2) 强制所有日志记录到在整个应用程序中使用的特定文件名。

在任何一种情况下,您都需要通过 SyncLock 块控制对关键功能的访问,例如打开、关闭、读取和写入,以确保如果您从线程记录或有多个实例共享同一个文件,则只有一个调用者正在执行代码同时。

在第一种情况下,您可能只想拥有一个实例。

在第二种情况下,您可以使用静态流编写器和静态方法,因为您不需要创建该类的新实例。这是我们多年前根据 Microsoft 在早期异常处理应用程序块中的指导实施的方法。

于 2012-08-06T21:27:32.867 回答
1

当我尝试创建它的新实例时,出现以下异常。

您应该在创建新实例之前处置当前实例。

也许你应该考虑单例模式。

于 2012-08-06T21:21:13.003 回答
0

永远只能有 1 个记录器实例。但是,Visual Studio 应用程序可能正在通过反射创建一个实例,因此它可以使用智能感知。a) 关闭宿主进程,b) 使用命令行编译。

为了解决您的特定问题,但是设计很糟糕。

于 2012-08-06T21:36:40.993 回答
0

我总是使用 append 属性进行日志记录,所以永远不要忘记打开的流

    public void Write(AppState state, String message)
    {

        StreamWriter sw = new StreamWriter(LogFileName, true);// true to append the new text
        sw.WriteLine(String.Format("{0}\r\n\t{1}", state, message));
        sw.Close(); // Close() is the same as Dispose()
    }
于 2012-08-06T21:23:02.970 回答
0

我能够重现错误 - 在第二行引发了异常:

var logger1 = new Logger();
var logger2 = new Logger();

但是,当我在第一个实例上使用 Write() 方法时,即:

var logger1 = new Logger();
logger1.Write("XYZ");
var logger2 = new Logger();

不再抛出异常。在您的情况下,它的行为方式是否相同?

问题是您对两个记录器使用相同的文件,如果您不关闭流或处置第一个实例,您基本上是在尝试为一个文件同时打开两个流。

尝试使用两个不同的文件(例如,您可以在构造函数中将路径传递给日志文件,而不是使用具有默认值的属性)并让我知道这是否解决了您的问题。

PS 但是,如果您需要两个记录器写入同一个文件并且它们应该能够同时访问该文件,那么您应该采用不同的方法 - 单例模式会更合适。

于 2012-08-06T21:32:29.367 回答