将using语句与已实例化的对象一起使用

时间:2013-09-02 11:08:30

标签: c# using-statement

我的应用程序中有一个非常简单的日志记录机制,它定期将一行写入文件(一个日志库对我的需求来说太过分了)看起来像这样:

private string logfile = @"C:\whatever.log";

public void WriteLine(string line)
{
   using(FileStream fs = File.Open(logfile, FileMode.Append))
   {
    // Log Stuff
   }
}

因此,只要我调用该方法,就会在完成日志记录后创建并处理新的FileStream。所以我考虑使用已经实例化的对象来阻止连续创建新对象:

private string logfile = @"C:\whatever.log";
private FileStream myStream = File.Open(logfile, FileMode.Append);

public void WriteLine(string line)
{
   using(myStream)
   {
    // Log Stuff
   }
}

但是,the MSDN reference discourages this(最后一个例子),由于范围问题。 那个案子做了什么?我的第一个例子中的开销是否可以忽略不计?

3 个答案:

答案 0 :(得分:3)

除了调用对象的using方法之外,Dispose()语句不做任何其他事情 因此,考虑到您的第二个示例,在第一次调用WriteLine(string)方法后,文件流将被释放。因此,在第一个之后,对此方法的任何其他调用都将导致异常。

使用Chris在评论中建议的File.AppendText()方法是一种方法。但请记住,使用此方法或任何其他File...方法也会打开一个流并在之后关闭并处理它。
它只会减少代码。

答案 1 :(得分:2)

第二种方法也会在每次调用WriteLine时处理流,因为您还使用using语句。 MSDN不鼓励这种方法,因为即使对象被处置,变量myStream仍然“存在”。所以这更容易出错。

如果您经常需要使用此方法,则应该使用using“在外面”或使用try-catch-finally

var myLogger = new MyLogger();
try
{      
    // here is your app which calls myLogger.WriteLine(...) often
}
catch(Exception ex)
{
    // log it
}
finally
{
    myLogger.Dispose(); // myLogger is your Log class, dispose should call myStream.Dispose();
}

答案 2 :(得分:1)

开销可能不可忽视,但这可能不是重点。

当您使用using时,创建,获取资源和处理已使用的资源的范围很大。你知道它的起始位置,使用位置以及它的完成位置。

如果你去第二个场景,你知道它的开始位置(它是在创建包含类的时候),但在那之后,你没有平台保证的方法来控制它的使用位置,以及在哪里(如果有的话)资源处理完毕。

如果这是关键代码,你自己可以做到这一点,并且你的包含类正确地实现IDisposable pattern,但这可能是棘手的,不适合胆小的人:)

但是,你在问题中说“一个日志库对我的需求来说太过分了”,所以我认为你的开销很小。恕我直言,您应该使用现成的File方法之一,例如File.AppendAllText

public void WriteLine(string line)
{
   //add an enter to the end
   line += Environment.NewLine;
   File.AppendAllText(logfile, line);
}

File.AppendAllLines

public void WriteLine(string line)
{
   File.AppendAllLines(logfile, new []{line});
}