5

Autofac を使用すると、次のコードを使用して、プロパティ インジェクションを使用してインターフェイスに対して解決するクラスを登録できます。

builder.RegisterType<Log4NetAdapter>()
       .As<ILogger>()
       .PropertiesAutowired()
       .InstancePerDependency();

ただし、私のLog4NetAdapterクラスには、呼び出し元のクラスの名前を必要とするコンストラクター パラメーターがあります。このようにして、呼び出し元のクラスの名前に基づいてイベントをログに記録できます。

public class Log4NetAdapter : ILogger
{
    private readonly ILog _logger;

    public Log4NetAdapter(string logName)
    {
        _logger = LogManager.GetLogger(logName);
    }

    ...
}

typeof(dependency).Name各依存関係に独自のLog4NetAdapterインスタンスがある場合、依存関係の名前 (つまり) をプロパティ注入クラスのコンストラクターに注入するにはどうすればよいですか?

4

2 に答える 2

4

更新: LogInjectionModuleサンプルと、 Autofacがプロパティ インジェクションを行う方法に基づいて構築し、コンストラクターとプロパティ インジェクションの両方を行うようにモジュールを拡張しました。

注:宣言型を使用するようLogManagerに渡される型を修正しました。OnComponentPreparingこれにより、たとえばResolve<Func<Service>>正しいログ タイプが使用されます。

    using System.Linq;
    using log4net;

    public class LogInjectionModule : Module
    {
        protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration)
        {
            registration.Preparing += OnComponentPreparing;
            registration.Activating += OnComponentActivating;
        }

        private static void OnComponentActivating(object sender, ActivatingEventArgs<object> e)
        {
            InjectLogProperties(e.Context, e.Instance, false);
        }

        private static void OnComponentPreparing(object sender, PreparingEventArgs e)
        {
            e.Parameters = e.Parameters.Union(new[]
                {
                    new ResolvedParameter(
                       (p, i) => p.ParameterType == typeof(ILog),
                       (p, i) => LogManager.GetLogger(p.Member.DeclaringType))
                });
        }

        private static void InjectLogProperties(IComponentContext context, object instance, bool overrideSetValues)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (instance == null) throw new ArgumentNullException("instance");

            var instanceType = instance.GetType();
            var properties = instanceType
                .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(pi => pi.CanWrite && pi.PropertyType == typeof(ILog));

            foreach (var property in properties)
            {
                if (property.GetIndexParameters().Length != 0)
                    continue;

                var accessors = property.GetAccessors(false);
                if (accessors.Length == 1 && accessors[0].ReturnType != typeof(void))
                    continue;

                if (!overrideSetValues &&
                    accessors.Length == 2 &&
                    (property.GetValue(instance, null) != null))
                    continue;

                ILog propertyValue = LogManager.GetLogger(instanceType);
                property.SetValue(instance, propertyValue, null);
            }
        }
    }

モジュールの使用方法については、次のサンプルを参照してください。

public class Service
{
    public Service(ILog log) { ... }
}

var cb = new ContainerBuilder();
cb.RegisterModule<LogInjectionModule>();
cb.RegisterType<Service>();
var c = cb.Build();

var service = c.Resolve<Service>();
于 2013-01-23T16:52:11.643 に答える
1

logNamean という名前で効果的に解決するためにILogのみ使用しILogます。

public class Log4NetAdapter : ILogger
{
    private readonly ILog _logger;

    public Log4NetAdapter(ILog logger)
    {
        _logger = logger;
    }

    ...
}

わかりましたので、問題を少し動かしましたが、これを他のクラス、つまりLogManager.

したがって、Unity を使用している場合は、適切なロガーを取得するために次のようにします。

var childContainer = container.CreateChildContainer();
childContainer.RegisterInstance<ILog>(LogManager.GetLogger(logName));
var adaptor = childContainer.Resolve<Log4NetAdapter>();

子コンテナは、他のコードがそれにアクセスするのを防ぎますILog。これは好きなだけ高くすることができます。私はあなたのコードについてこれ以上知りません。

于 2013-01-23T16:46:27.007 に答える