如果我在整个应用程序生命周期中需要它,可以在哪里放置StreamWriter?

Where to dispose StreamWriter if I need it during entire application lifetime? I'm going to dispose it in destructor, will that work? I have to dispose to flush data, and I don't want to use AutoFlush feature because from msdn: "You can get better performance by setting AutoFlush to false, assuming that you always call Close (or at least Flush) when you're done writing with a StreamWriter."

所以我应该像下面的代码一样在析构函数中处理 Dispose

class Log
{
    private static StreamWriter swLog = new StreamWriter("logMAIN.txt");

    static ~Log()
    {
        swLog.Dispose();
    }

    public static void Push(LogItemType type, string message)
    {
        swLog.WriteLine(type + " " + DateTime.Now.TimeOfDay + " " + message);
    }
}

upd instead of Dispose i meant to call Close but it is not improtant in this case because they seems doing exactly the same.

0
额外 编辑
意见: 1
如果你正在做日志记录考虑使用现有的追踪框架(一个是.Net框架的一部分,或者一个可能是外部的如Log4Net)已经解决了你将要发现和将来发现的所有问题(如多线程访问,日志轮转,IO故障,可扩展性...)。
额外 作者 Alexei Levenkov,
只需使用 File.WriteAllText 并且不要打扰 StreamWriter
额外 作者 Bali C,

2 答案

您似乎基于您决定不使用MSDN的某些性能信息刷新。那不是我开始的地方。

您是否有证据使用AutoFlush导致您的显着性能问题?

您是否考虑以不同的方式缓解这些性能问题,例如有一个线程写入 StreamWriter ,可以自动刷新或每20秒钟周期性刷新一次?

您还没有告诉我们您正在编写什么样的应用程序,请关注您 - 这会对您关于关机的知识产生重大影响。

另请注意,您提供的代码在开始时不是线程安全的。您最终可能会同时使用来自多个线程的 StreamWriter ;我怀疑 StreamWriter 是特别为这种情况设计的。

0
额外
有些日志是多线程的,我在这种情况下使用了 lock(this)内部的 Push 方法。我想我不使用后台线程(但我使用<�代码>任务。感谢乔恩我想我会只使用 AutoFlush ,直到这成为一个问题
额外 作者 javapowered,
它只是控制台应用程序
额外 作者 javapowered,
为什么我不能实现这么简单的事情:“保持streamwriter打开,直到外部类处理完,当外部类被处理时刷新磁盘上的所有内容”。
额外 作者 javapowered,
应用程序用于HFT交易。嗯,是的,我退出时,只有当应用程序关闭:)或你的意思是由 exit points
额外 作者 javapowered,
我的应用程序中有许多不同的日志,其中一些日志只用于一个线程。可能 AutoFlush 功能对我来说很好,但由于我不需要立即记录日志,所以我正在考虑不使用它。我没有理由使用 AutoFlush ,并且它在.NET中默认关闭,因此我决定使用“默认”方案。
额外 作者 javapowered,
@javapowered:“我没有理由使用AutoFlush” - 除此之外,即使您的应用程序已关闭,您也要确保不会丢失任何日志。你还没有解释你正在写什么类型的应用程序,以及你是否有一个明确定义的退出点......
额外 作者 Jon Skeet,
@javapowered:你可以。但是,您还没有告诉我们它是什么类型的应用程序 - Web应用程序,富客户端等。如果您可以告诉合适的时间处理您的日志,那么确定 - 然后处置它们。
额外 作者 Jon Skeet,
@javapowered:好的,最后,一些信息。你有多个线程,还是只有一个线程?如果你有多个线程,是否有后台线程?如果你可以在你退出的时候干净地处理所有东西,这将是最简单的方法......尽管这意味着你可能会发现 IDisposable 一直偷偷摸摸通过你的代码,只是为了记录。我仍然会敦促你至少考虑自动冲洗......
额外 作者 Jon Skeet,

问题的确是 StreamWriter 被初始化的方式。使用这样的常规对象

using (var logger = new Log())
{
    app.Run();
}

StreamWriter 仍然可以是 Log 类中的静态字段,但是可以在已知时间点进行初始化和处理,而不是使用静态初始化程序。

为此,您需要让Log类实现 IDisposable 接口,并像下面这样在 Dispose 方法中处理 StreamWriter

class Log: IDisposable
{
    private static StreamWriter swLog;

    public Log()
    {
       swLog = new StreamWriter("logMAIN.txt");
    }

    public void Dispose()
    {
        swLog.Dispose();
    }

    public static void Push(LogItemType type, string message)
    {
        swLog.WriteLine(type + " " + DateTime.Now.TimeOfDay + " " + message);
    }
}

还要注意,即使抛出异常, Log 也将被丢弃。

0
额外
如果我有几个(或几十个)不同的日志,我应该使用块编写大量嵌套的代码块?
额外 作者 javapowered,
@JonSkeet我的不好,让我们从析构函数中移除 static ,并假定这个类只用于一个线程......但是我也需要多线程版本
额外 作者 javapowered,
@vidstige:原始代码甚至不会编译,因为没有静态终结器这样的事情。但是,提出一个解决方案,使构造中的静态变量发生变化并不是一个好的答案,IMO。
额外 作者 Jon Skeet,
@vidstige:其实现在情况更糟。现在,如果你有两个使用块在不同的线程中创建不同的实例,你可以在一个线程中处理 StreamWriter ,而你试图在另一个线程中使用它。哎哟。显然,如果你的应用程序很简单,并且有一个控制良好的退出点,那么问题就很简单。我会想象情况并非如此,尽管OP没有说这是什么类型的应用程序。
额外 作者 Jon Skeet,
@javapowered:现在你假设你的终结器将在基础流的终结器之前执行。这不能保证。基本上,你不应该在这种情况下使用终结器。
额外 作者 Jon Skeet,
你还没有解释StreamWriter将如何“在已知的时间点进行初始化和处置” - 在这里丢弃是重要的一点。
额外 作者 Jon Skeet,
@Jon这也是原始代码中的问题。记住终结器运行在它自己的线程中。从多个线程访问的问题只是模糊地涉及到关于放置StreamWriter时的问题。我的假设与你猜测相反,应用程序有一个明确的退出点。
额外 作者 vidstige,
@Jon true。编辑后希望这部分更清晰一些
额外 作者 vidstige,
是的,为什么不呢?或者创建一个新的类,该类有一个在 it 处置时被处理的日志列表。一个班级,一个责任。
额外 作者 vidstige,