解決策は、単純なロガー ファサードを作成して、Ninject をアプリの残りの部分から完全に切り離すことです。手順は次のとおりです。
1) Ninject の ILogger インターフェイスをコピーしてアプリの名前空間に貼り付けます (Ninject の ILogger を介して公開される型のために、Ninject のアセンブリに依存するだけでは継承しないでください)。
2) カスタム Logger、LoggerFactory、および LoggerModule クラスを作成します。
3) LoggerModule を Ninject の StandardKernel に渡す
完全を期すために、コードは次のとおりです。
Ninject のILogger - ILogger インターフェイスをコピーして貼り付け、名前空間を MyAppNamespace.Logger に変更し、次のメソッドを追加します。
void Debug(string message);
void Info(string message);
void Trace(string message);
void Warn(string message);
void Error(string message);
void Fatal(string message);
Logger.cs
namespace MyAppNamespace.Logger
{
using System;
class Logger : Ninject.Extensions.Logging.Log4net.Infrastructure.Log4NetLogger, ILogger
{
private const string DumpVerbatimFormat = "{0}";
public Logger(Type type)
: base(type)
{
}
public void Debug(string message)
{
base.Debug(DumpVerbatimFormat, message);
}
public void Info(string message)
{
base.Info(DumpVerbatimFormat, message);
}
public void Trace(string message)
{
base.Trace(DumpVerbatimFormat, message);
}
public void Warn(string message)
{
base.Warn(DumpVerbatimFormat, message);
}
public void Error(string message)
{
base.Error(DumpVerbatimFormat, message);
}
public void Fatal(string message)
{
base.Fatal(DumpVerbatimFormat, message);
}
}
}
LoggerFactory.cs
namespace MyAppNamespace.Logger
{
using System;
using System.Collections.Generic;
static class LoggerFactory
{
public static ILogger GetLogger(Ninject.Activation.IContext context)
{
return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType);
}
private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>();
private static ILogger GetLogger(Type type)
{
lock (TypeToLoggerMap)
{
if (TypeToLoggerMap.ContainsKey(type))
return TypeToLoggerMap[type];
ILogger logger = new Logger(type);
TypeToLoggerMap.Add(type, logger);
return logger;
}
}
}
}
LoggerModule.cs
namespace MyAppNamespace.Logger
{
public class LoggerModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
log4net.Config.XmlConfigurator.Configure();
Bind<ILogger>().ToMethod(LoggerFactory.GetLogger);
}
}
}
この混乱全体を別のクラス ライブラリに押し込んで、Ninject のロギング拡張機能と具体的なロガーに依存する唯一の部分にします。次のように、アプリ全体で MyAppNamespace.ILogger を使用できるようになりました。
LoggerTest.cs
namespace MyAppNamespace.Whatever
{
using Logger;
public class LoggerTest
{
public LoggerTest(ILogger log)
{
Log.Info("Logger starting up");
}
}
}
Main.cs のどこかに
using (IKernel kernel = new StandardKernel(new Logger.LoggerModule()))
{
kernel.Get<LoggerTest>();
}
Main は最終的に Ninject に依存しますが、ロギング拡張機能や使用するロガーには依存しません (コードは Log4Net で動作します。NLog 用に少し調整する必要があります)。アプリの他の部分は MyAppNamespace.ILogger に依存します。それはそれについてです。