Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF:我应该在日志中使用字符串ob StringBuilder吗_Wpf_Multithreading_Log4net - Fatal编程技术网

WPF:我应该在日志中使用字符串ob StringBuilder吗

WPF:我应该在日志中使用字符串ob StringBuilder吗,wpf,multithreading,log4net,Wpf,Multithreading,Log4net,因此,我有WPf应用程序和Log4Net,所以每次我想添加log时,我都是这样添加的: log4net.Info("bla bla"); LoggerForm loggerForm = new LoggerForm(); loggerForm.Show(); 此外,我想添加记录器表单,因此我创建了另一个表单,并从我的主表单以以下方式打开它: log4net.Info("bla bla"); LoggerForm loggerForm = new LoggerForm(); loggerFo

因此,我有
WPf
应用程序和
Log4Net
,所以每次我想添加
log
时,我都是这样添加的:

log4net.Info("bla bla");
LoggerForm loggerForm = new LoggerForm();
loggerForm.Show();
此外,我想添加记录器
表单
,因此我创建了另一个
表单
,并从我的主
表单
以以下方式打开它:

log4net.Info("bla bla");
LoggerForm loggerForm = new LoggerForm();
loggerForm.Show();
并创建日志
对象

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
对象,并将每个
LogEvent
添加到此
列表中:

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);
            }));
        }
    }
}
此行:

LogHelper.AddLogToList = true;
指示已打开我的日志
窗体
,以便我可以将我的
LogEvent
i插入我的列表

收藏更改:

LogHelper.AddLogToList = true;
每次新的
LogEvent
添加到我的
列表中
我都会将我的
ItemSource
更新到我的
列表视图中

ListView lvLogger;

private void LogEntries_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    lvLogger.ItemsSource = LogHelper.LogEntries;
}
好的,这就是我的问题:

LogHelper.AddLogToList = true;
  • 每次我想创建新的
    Log
    时,我都会键入两次:

    log.Info("bla bla");
    LogHelper.AddLog(Level.Info, "bla bla", $"MyClassName\\MyMethodName"); 
    
    正如您所看到的,我在这里使用了两次字符串,所以我想知道是否最好使用
    string.Builder
    而不是
    string

  • 我还想提到,我通过不同的线程更新日志

  • 当我的记录器
    窗体
    关闭时,我注册到其关闭
    事件
    并清除我的
    日志事件
    列表:

    private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        LogHelper.AddLogToList = false;
        LogHelper.LogEntries.Clear();
    }
    
    所以我这里的问题是,我是否应该在这里注销我的
    日志条目\u CollectionChanged
    事件:

    LogHelper.LogEntries.CollectionChanged-=LogEntries\u CollectionChanged

  • 或者这是多余的?

    1)只有在多次重复追加文本时,Stringbuilder才值得使用。除非你这么做,否则我就用一根绳子。 如果这是你正在做的,那么也许你不应该这样做

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

    log.Info(message);
    LogHelper.AddLog(Level.Info, message, $"MyClassName\\MyMethodName");
    
    2) 这一部分我读了好几遍,都弄糊涂了。不过,作为一项一般原则,如果您订阅的事件不是私人成员,那么您应该取消订阅该事件,以避免任何内存泄漏。因此,如果集合是由不同的窗口或其他对象更新的,那么您应该取消订阅该处理程序,以便在不再需要该窗口的实例时可以对其进行垃圾收集

    从注释中的进一步解释可以看出,您可能只需按减少的日期时间对集合进行排序,并在顶部查看最新的日志条目。这将完全避免collectionchanged事件处理程序。collectionview的排序:

    经过更多的解释。。。 文本文件似乎是用于显示的。 我认为您应该完全忘记文本文件,使用observablecollection作为循环列表

    您正在对日志项调用add方法:

    LogEntries.Add(logEntry);
    
    这样做的目的是将其附加到集合中。您可以改为使用insert在特定索引处插入

    LogEntries.Insert(0, logEntry);
    
    这将增加收藏的“顶部”。 我认为这也可以避免排序。 你不想让这个收藏变得庞大,所以一旦你点击了一个数字(比如100),你就可以删除最古老的

    LogEntries.RemoveItem(100);
    
    记得先检查你有超过100个条目,否则会出错


    你可能想考虑更进一步的问题。我们只知道你告诉我们什么,人们不太可能长时间坐在那里思考你在做什么而意识到。。。“嘿,这就是所有的日志,文件可能相当大”

    使用
    StringBuilder
    不会减少代码。如果您想要更少的代码,请放入
    log4net.Info(“bla-bla”)在LogHelper中,或创建同时执行两个作业的内容

    StringBuilder
    在这里不相关,因为
    Andy
    StringBuilder只有在多次重复添加文本时才值得使用。


    更多信息->

    我忘了提到log.Info(例如)是我的txt文件日志,而我的LogHelper.AddLog是我的logger表单中的ListView,只有当用户希望打开此logger表单并以更方便的方式查看它,然后查看txt文件时,才可以在文件中添加新字符串。将整个文件保存在内存中听起来不是一个好计划。如果我理解你的意思,你有什么建议?只要把我的字符串放进一个变量,这个字符串就会传递到我的两个日志对象中?(顺便说一句,我的列表最多有1000个条目,当我的列表大约有1000个条目时,我会开始删除第一个条目)我不明白为什么你想要一个txt文件和一个日志文件,但是的,我只会将相同的参数传递给两个方法。因为我的txt文件可以容纳许多条目,我有高达10MB的文件,其中包含不断增长的文件和最多3个文件,如果我在LisyView中放入如此多的条目,我的记忆就会崩溃。我的问题是(将它们放在同一个函数中)我的log4net配置为同时向我显示类名和方法([%logger/%method])因此,如果我将其放在一个函数中,所有条目将来自同一位置,而不是来自原始位置。顺便说一句,因为StringBuilder只有在多次重复添加文本时才有效-创建静态StringBuilder并将我的所有日志消息放在该对象中是否更好?否,创建静态
    StringBuilder
    也不会有任何改善,要从包装的类中收集正确的方法名,可以在此处进行检查