将位置字符串更改为const会破坏我的记录器类

Dav*_*vid 5 c# mono multithreading const readonly

我一直在努力解决最近出现的一个问题,我写的是一个简单的logtofile类.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace Assets.Code
{
    class TimingLogger
    {
        public static readonly TimingLogger Logger = new TimingLogger();
        private static readonly string path = "C:\\Logs\\TimingLog.txt";
        private readonly Mutex mutex = new Mutex(false, path);
        private StreamWriter writer;
        private readonly Queue<string> queue = new Queue<string>();
        private bool isRunning;
        private readonly object obj = new object();

        private TimingLogger()
        {

        }

        public void CheckPath()
        {
            if (!File.Exists(path))
            {
                File.Create(path);
            }
        }

        public void Run()
        {
            isRunning = true;
            while (isRunning)
            {
                lock (obj)
                {
                    while (queue.Count <= 0)
                    {
                        Monitor.Wait(obj);
                    }
                    Log(queue.Dequeue());
                }
            }
        }

        public void Log(string line)
        {
            try
            {
                mutex.WaitOne();
                writer = File.AppendText(path);
                writer.WriteLine(line);
                writer.Close();
            }
            catch (Exception)
            {
                //throw;
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }

        public void Enqueue(string line)
        {
            lock (obj)
            {
                queue.Enqueue(line);
                Monitor.Pulse(obj);
            }
        }

        public void Stop()
        {
            isRunning = false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

直到最近,当我注意到我的日志文件没有显示我预期的数据时,这个类工作正常.奇怪的是,我没有改变班级的任何功能.比较老,正与我的新一个版本,唯一的区别是,我的一些领域作了privatereadonly.除此之外,string path改为const.令我完全困惑的是,改回来readonly修复我遇到的问题.

所以我的问题是:这究竟是怎么回事?据我所知,在这种情况下,readonly和const之间在功能上应该没有任何区别.

调试时,行为的变化很大,特别是在Run()方法中.这里应该发生的是,一旦Log(queue.Dequeue());被调用,线程将离开lock语句并while (isRunning)再次遍历循环.这看起来很明显,对吗?但是,当我再次更改string pathto const和debug时,Log(queue.Dequeue());会传递一次,并且可以在日志文件中找到单个语句,之后它再也不会执行任何其他操作.它没有while (isRunning)再次过去,它似乎没有离开lock (obj)块.成功调用Log(queue.Dequeue());一次后,记录器线程似乎只是关闭或暂停.

实际上在Log方法中抛出异常没有任何区别,因为日志记录本身工作正常,所以不会抛出异常.

我应该提一下,我在使用Mono的Unity3D 5中使用此代码.但是,通过如此小的编辑,这种行为的剧烈变化对我来说似乎是不可能的.任何人都可以解释为什么会这样吗?

谢谢!

Rod*_*pez 1

区别如下:

常量是在文件的元数据中创建的,因此当您运行类时,该值已经存在。

ReadOnly 在编译时初始化,在您的情况下,这就是技巧,即使您首先声明路径然后互斥体,编译器也会首先初始化互斥体对象,原因如下:

您要初始化的第一个静态对象是 Logger:

public static readonly TimingLogger Logger = new TimingLogger();
Run Code Online (Sandbox Code Playgroud)

因为您调用了构造函数,所以非静态成员被初始化,从而使互斥体成为下一个要初始化的成员。此时您还没有初始化路径,因此您正在使用参数 false 和 null 创建互斥对象。

如果您希望出现与使用 readonly 的 const 相同的错误,您可以使用静态构造函数强制静态参数初始化的顺序,例如:

static TimingLogger()
{
    path = "C:\\Logs\\TimingLog.txt";
    Logger = new TimingLogger();
}
Run Code Online (Sandbox Code Playgroud)

或者只是将路径放在记录器之前。

如果您不想使用 const 时出现错误,只需使用 null 参数更改互斥体初始化即可:

private readonly Mutex mutex = new Mutex(false, null);
Run Code Online (Sandbox Code Playgroud)