【问题标题】:WPF: should i use string ob StringBuilder with my LogWPF:我应该在我的日志中使用字符串 ob StringBuilder
【发布时间】:2018-03-27 08:19:20
【问题描述】:

所以我有WPf 应用程序和Log4Net所以每次我想添加log 我只是这样添加:

log4net.Info("bla bla");

此外,我想添加记录器form,所以我创建了另一个form,并从我的主form 以这种方式打开它:

LoggerForm loggerForm = new LoggerForm();
loggerForm.Show();

并创建日志object

public class LogEntry : PropertyChangedBase
{
    public string DateTime { get; set; }
    public int Index { get; set; }
    public string Source{ get; set; }
    public Level Level { get; set; }        
    public string Message { get; set; }
}

LogHelper 将这个LogEvent 对象保存在List 中,并将每个LogEvent 添加到这个List 中:

public static class LogHelper
{
    public static ObservableCollection<LogEntry> LogEntries { get; set; }
    public static bool AddLogToList { get; set; }

    private static int Index;

    public static void AddLog(Level level, string message, string source)
    {
        if (AddLogToList)
        {
            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                if (LogEntries.Count == 1000)
                    LogEntries.RemoveAt(0);

                LogEntry logEntry = new LogEntry()
                {
                    DateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff"),
                    Index = Index++,
                    Level = level,
                    Source = source,
                    Message = message.Trim()
                };

                LogEntries.Add(logEntry);
            }));
        }
    }
}

然后从我的记录器formInitializeComponent 注册到我的列表CollectionChanged

LogHelper.AddLogToList = true;
LogHelper.LogEntries.CollectionChanged += LogEntries_CollectionChanged;

这一行:

LogHelper.AddLogToList = true;

表示我的 Logger form 已打开,因此我可以将我的 LogEvent 插入到我的列表中。

CollectionChanged:

每次将新的LogEvent 添加到我的List 时,我都会将我的ItemSource 更新为我的ListView

ListView lvLogger;

private void LogEntries_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    lvLogger.ItemsSource = LogHelper.LogEntries;
}

好的,这些是我的问题:

  1. 每次我想创建新的Log 我都会输入两次:

    log.Info("bla bla");
    LogHelper.AddLog(Level.Info, "bla bla", $"MyClassName\\MyMethodName"); 
    

    所以你可以看到我在这里使用了两次字符串,所以我想知道这是否会更好地使用 String.Builder 而不是 string

我还想提一下,我通过不同的线程更新我的日志。

  1. 当我的 Logger form 关闭时,我注册到它的关闭 event 并清除我的 LogEvent 列表:

    private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        LogHelper.AddLogToList = false;
        LogHelper.LogEntries.Clear();
    }
    

    所以我的问题是我应该在这里取消注册我的LogEntries_CollectionChanged 事件:

    LogHelper.LogEntries.CollectionChanged -= LogEntries_CollectionChanged;

或者这是多余的?

【问题讨论】:

    标签: wpf multithreading log4net


    【解决方案1】:

    1) Stringbuilder 仅在您多次重复附加文本时才值得使用。除非那是你正在做的,否则我只会使用一个字符串。 如果这是你正在做的,那么也许你不应该这样做。

    查看您的代码,您似乎已经有了一个消息变量,所以我可能对这部分关于使用它两次的内容感到有些困惑。也许你不是在谈论消息。 我会将一个字符串传递给一个方法,并在你的两行代码中使用该变量。假设它们使用相同的方法。

    log.Info(message);
    LogHelper.AddLog(Level.Info, message, $"MyClassName\\MyMethodName");
    

    2) 这部分我读了好几遍,很混乱。不过,作为一般原则,如果您订阅的不是私有成员的事件,那么您应该取消订阅该事件以避免任何内存泄漏。因此,如果集合是由不同的窗口或其他东西更新的,那么您应该取消订阅该处理程序,以便该窗口的实例在您不再需要时可以被垃圾回收。

    从 cmets 的进一步解释中可以看出,您可能只需按递减的日期时间对集合进行排序,然后在顶部查看最新的日志条目。这将完全避免 collectionchanged 事件处理程序。 collectionview的排序: https://social.technet.microsoft.com/wiki/contents/articles/26673.wpf-collectionview-tips.aspx#Sorting

    经过更多的解释...... 看来文本文件是为了显示。 我认为您应该完全忘记文本文件并使用 observablecollection 作为循环列表。

    你正在调用 logentries 的 add 方法:

    LogEntries.Add(logEntry);
    

    它的作用是附加到集合中。您可以改为使用 insert 在特定索引处插入。

    LogEntries.Insert(0, logEntry);
    

    这增加了集合的“顶部”。 我认为这也可以避免排序。 您不希望该集合变得庞大,因此一旦您点击一个数字(例如 100 ),您就可以删除最旧的。

    LogEntries.RemoveItem(100);
    

    记得先检查你有超过 100 个条目,否则会出错。

    您可能需要考虑对任何其他问题进行更全面的解释。我们只知道您告诉我们的内容,人们不太可能坐在那里思考您在做什么足够长的时间来意识到......“嘿,这就是所有的日志,文件可能非常大”。

    【讨论】:

    • 我忘了提到 log.Info(例如)是我的 txt 文件日志,而我的 LogHelper.AddLog 是我的记录器表单中的 ListView,只有当用户想要打开这个记录器表单并且以更方便的方式查看它然后查看txt文件
    • 类似 File.AppendText 的东西可以将新字符串添加到文件中。将整个文件保存在内存中听起来不是一个好计划。如果我遵循你的意思。
    • 你有什么建议?只需将我的字符串放入一个变量中,然后此字符串将传递给我的 2 个日志对象? (顺便说一句,我的列表最多包含 1000 个条目,并在我的列表大约有 1000 个条目时开始删除第一个)
    • 我不明白你为什么想要一个 txt 文件和一个日志文件,但是是的,我只是将相同的参数传递给两个方法。
    • 因为我的 txt 文件可以容纳许多条目,而且我有多达 10MB 的文件,而且文件越来越多,最多可以有 3 个文件,如果我在 LisyView 中放入这么多条目,我的记忆就会崩溃
    【解决方案2】:

    使用StringBuilder 不会减少您的代码。如果您想要更少的代码,请将 log4net.Info("bla bla"); 放在 LogHelper 中,或者创建同时完成这两项工作的东西。

    StringBuilder 在这里不相关,因为AndyStringbuilder is only worth using if you're repeatedly appending text numerous times.

    更多信息->String vs Stringbuilder

    【讨论】:

    • 我的问题是(将它们放在同一个函数中)是我的 log4net 配置为向我显示类名和方法([%logger/%method])所以如果我把在一个函数中,所有条目都将来自同一位置,而不是来自原始位置
    • 顺便说一句,因为 StringBuilder 只有在多次重复附加文本的情况下才能创建静态 StringBuilder 并将我的所有日​​志消息放入此对象中会更好吗?
    • 不,创建静态 StringBuilder 也不会变得更好,并且要从包装类中收集正确的方法名称,您可以在此处查看 stackoverflow.com/questions/1149844/…
    猜你喜欢
    • 2014-05-27
    • 1970-01-01
    • 2022-10-14
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多