usar una reemplazar recortar quitar longitud extraer ejemplos como caracteres cadena c# multithreading mono const readonly

c# - reemplazar - Cambiar una cadena de ubicación a const rompe mi clase de registrador



string c# ejemplos (1)

He estado luchando con un problema que apareció recientemente con una clase simple de registro de datos que escribí.

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; } } }

Esta clase estuvo funcionando bien hasta hace poco, cuando noté que mi archivo de registro no mostraba los datos que esperaba. Por extraño que parezca, no había cambiado ninguna funcionalidad de la clase. Comparando una versión antigua y funcional con la nueva, la única diferencia fue que algunos de mis campos se hicieron de forma private y de forma readonly . Además de eso, la string path la string path se cambió a const . Y para mi completo desconcierto, cambiar esto de vuelta a readonly resolvió el problema que estaba teniendo.

Entonces mi pregunta es: ¿cómo diablos es esto posible? Por lo que yo sé, no debería haber ninguna diferencia funcional entre readonly y const en esta situación.

Al depurar, el cambio en el comportamiento es sustancial, especialmente en el método Run() . Lo que debería suceder aquí es que una vez Log(queue.Dequeue()); ha sido llamado, el hilo saldrá de la instrucción de lock e while (isRunning) nuevamente a través del while (isRunning) . Esto parece bastante obvio, ¿verdad? Sin embargo, cuando cambio la string path la string path a const y a la depuración de nuevo, el Log(queue.Dequeue()); se pasa una vez y se puede encontrar una sola declaración en el archivo de registro, después de lo cual simplemente ya no hace nada más. No pasa de nuevo while (isRunning) nuevo y no parece dejar el lock (obj) . El hilo del registrador parece simplemente apagar o pausar después de llamar con éxito a Log(queue.Dequeue()); una vez.

En realidad, lanzar la excepción en el método de Log no hace diferencia, no se lanzan excepciones porque el registro funciona bien.

Debo mencionar que estoy usando este código con Unity3D 5, que usa Mono. Pero aún así, este cambio drástico en el comportamiento por una edición tan pequeña me parece imposible. ¿Puede alguien explicar por qué ocurre esto?

¡Gracias!


Aquí está la diferencia:

Las ventajas se crean en los metadatos de los archivos, por lo que cuando ejecutas tu clase, el valor ya está allí.

ReadOnly se inicializa en tiempo de compilación, en su caso, aquí está el truco, aunque usted haya declarado la ruta primero, luego la exclusión mutua, el compilador inicializó primero el objeto mutex, aquí es por qué:

Su primer objeto estático para ser inicializado es el Registrador:

public static readonly TimingLogger Logger = new TimingLogger();

Como ha llamado al constructor, los miembros no estáticos se inicializan, lo que hace que mutex sea el siguiente miembro en inicializarse. En este punto, aún no ha inicializado la ruta, por lo que está creando su objeto mutex con los parámetros falso y nulo.

Si quiere tener el mismo error que tiene con const usando readonly, puede forzar el orden de inicialización de sus parámetros estáticos usando un constructor estático como:

static TimingLogger() { path = "C://Logs//TimingLog.txt"; Logger = new TimingLogger(); }

O simplemente poniendo el camino antes de Logger.

Si no desea tener el error al usar const, simplemente cambie la inicialización mutex usando el parámetro null:

private readonly Mutex mutex = new Mutex(false, null);