3

以下が可能かどうか、また可能であればどうすればよいか疑問に思っています。以下のコードで説明してみます。

public class RandomClass
{
    ...
    //class is filled with stuff of none importance for this demonstration
    ...

    [LogScope("Start", "End")] //The important LogScope attribute!
    public virtual void MyMethod()
    {
        ...
        //Doing something here but not the point now...
        ...
    }

    ...
}

public LogScopeAttribute : InterceptAttribute
{
    private readonly string _header;
    private readonly string _footer;

    public LogScopeAttribute(string header, string footer)
    {
        _header = header;
        _footer = footer;
        // This is just one of many constructors....
    }

    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return request.Context.Kernel.Get<LogScopeInterceptor>(
            new ConstructorArgument("header", _header),
            new ConstructorArgument("footer", _footer));
        // In the real version of this method there is more logic here for creating
        // the right version of the interceptor, in regards to what constrcutor the
        // LogScopeAttribute was called with.
    }
}

public class LogScopeInterceptor : SimpleInterceptor
{
    // No need to explain stuff here, (not of importance to the question)
    // but what the interceptor does for me is write to log
    // a header and footer and indent everything inside the logscope.
}

私が欲しいのは、メソッド内でカーネルを呼び出す必要がないように、Ninject を使用してILogScopeInterceptorFactoryaを挿入し、オブジェクトを挿入することです。このようにしたい...LogScopeAttributeCreateInterceptorConstructorArgument

public LogScopeAttribute : InterceptAttribute
{
    private readonly string _header;
    private readonly string _footer;
    private readonly ILogScopeInterceptorFactory _logScopeInterceptorFactory;

    public LogScopeAttribute(ILogScopeInterceptorFactory logScopeInterceptorFactory ,string header, string footer)
    {
        _header = header;
        _footer = footer;
        _logScopeInterceptorFactory = logScopeInterceptorFactory;
    }

    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return _logScopeInterceptorFactory.Create(_header, _footer);
    }
}

これは、次の ようILogScopeInterceptorFactoryにバインドするインターフェイスです。Ninject.extensions.Factory

Bind<ILogScopeInterceptorFactory>().ToFactory();

public interface ILogScopeInterceptorFactory
{
    LogScopeInterceptor Create(char separatorChar, string header, string footer);
    LogScopeInterceptor Create(char separatorChar, string header);
    LogScopeInterceptor Create(string header, string footer);
    LogScopeInterceptor Create(string header);
    LogScopeInterceptor Create(char separatorChar);
    LogScopeInterceptor Create();
}

今私がやりたいことは、ファクトリを手動で挿入することなく、単に注入するだけで、LogScopeAttributeこのようなもの を使用することです。どうすればそれを行うことができますか?[LogScope("Start", "End")]

EDIT2:

私は log4net を使用してログを記録しています。ここでLogScopeAttributeは、何が行われているか、出力がどのように見えるかを書きます。

[LogScope("The Start", "The End")]
public virtual void MyMethod()
{
    logger.Info("Hello World!");
}

OUTPUT:
logger: The Start
logger:     Hello World!
logger: The End

ninject がすべてのメソッドをインターセプトするには、それらが and である必要がpublicありvirtualます。これはロギングに非常に便利で、メソッド内に記録されたすべてのものを簡単にインデントできます。ヘッダーとフッターが必要な場合、またはメソッドの実行時間をすべてそこに出力します。これはネストすることもできます...

@フェリックス

問題は、カーネルを取得できないことではありません...カーネルを呼び出してファクトリを作成したい場合は、次のようにすることができます。

public override IInterceptor CreateInterceptor(IProxyRequest request)
{
    var factory = request.Context.Kernel.Get<ILogScopeInterceptorFactory>();
    return factory.Create(_header, _footer);
}

ファクトリを手動で挿入した場合、すべての属性に対してこれを行う必要があります

[LogScope(_logScopeInterceptorFactory, "header", "footer")]

そして、それはただの醜いものです

4

1 に答える 1

0

属性のように実行時に何もできないので...チートする必要があります...

コンテナーはグローバルなので、常にシングルトン パターンを使用して作成します...

public static class Container
{
    private static IKernel _container;

    static Container()
    {
        _container = ...; //Create the kernel and define container
    }

    public static IKernel Current { get { return _container; } }
}

public LogScopeAttribute(string header, string footer)
{
    _header = header;
    _footer = footer;
    _logScopeInterceptorFactory = Container.Current.Get<ILogScopeInterceptorFactory>();
}

もちろん、通常は を使用するのContainer.Current.Getはアンチパターンです。ただし、状況によっては必須です (属性など)。理想的な世界では、属性は非常にスリムで、ILogScopeInterceptorFactoryすべての作業を行います (そしてテストされるクラスになります)。

于 2013-01-29T10:48:24.173 に答える