コード内のどこからでもログにアクセスできるログ サービスを作成しようとしているようです。スレッドについて言及しているため、注意してその同期を適切に処理する必要があります。
ILogger
最初に次のようなインターフェイスを作成します。
public interface ILogger
{
void Log(string line);
void Log(string format, params object[] args);
}
次に、適切なLogger
基本クラス:
public abstract class Logger : ILogger
{
public abstract void Log(string line);
public virtual void Log(string format, params object[] args)
{
Log(string.Format(format, args));
}
}
もちろん、実際の実装が必要になります。
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class ConcurrentLogger : Logger, ILogger, IDisposable
{
bool isDisposed;
BlockingCollection<string> loggedLines;
Action<string> callback;
public ConcurrentLogger(Action<string> callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
var queue = new ConcurrentQueue<string>();
this.loggedLines = new BlockingCollection<string>(queue);
this.callback = callback;
StartMonitoring();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool isDisposing)
{
if (isDisposed) return;
if (isDisposing)
{
if (loggedLines != null)
loggedLines.CompleteAdding();
}
isDisposed = true;
}
public override void Log(string line)
{
if (!loggedLines.IsAddingCompleted)
loggedLines.Add(line);
}
protected virtual void StartMonitoring()
{
Task.Factory.StartNew(() =>
{
foreach (var line in loggedLines.GetConsumingEnumerable())
{
if (callback != null)
callback(line);
}
loggedLines.Dispose();
}, TaskCreationOptions.LongRunning);
}
}
グローバル アクセスにはクラスが必要Singleton
になるため、このLogManager
クラスを作成します。
public sealed class LogManager : ILogger
{
#region Singleton
static readonly LogManager instance = new LogManager();
public static LogManager Current { get { return instance; } }
private LogManager() { } // Disallow creating instances.
#endregion
ILogger logger;
public ILogger Logger { get { return logger; } }
public void StartLogging(ILogger logger)
{
if (logger == null)
throw new ArgumentNullException("logger");
this.logger = logger;
}
public void StopLogging(bool dispose = true)
{
var previousLogger = this.logger as IDisposable;
this.logger =null;
if (previousLogger != null && dispose)
previousLogger.Dispose();
}
public void Log(string line)
{
if (logger != null) logger.Log(line);
}
public void Log(string format, params object[] args)
{
if (logger != null) logger.Log(format, args);
}
}
いくつかの簡単な初期化を行うと:
void InitializeLog()
{
var log = new ConcurrentLogger(LogToTextBox);
LogManager.Current.StartLogging(log);
}
void LogToTextBox(string line)
{
if (!CheckAccess())
{
this.Dispatcher.BeginInvoke((Action<string>)LogToTextBox,
DispatcherPriority.Background,
line);
return;
}
logTextBox.AppendText(line + Environment.NewLine);
}
次に、コードのどこでも呼び出すことができます:LogManager.Current.Log(...);