Dependency injection 多线程环境中的Ninject拦截

Dependency injection 多线程环境中的Ninject拦截,dependency-injection,ninject,ninject-interception,Dependency Injection,Ninject,Ninject Interception,我正在尝试使用Ninject.Extensions.Interception.dynamicxproxy创建一个拦截器来记录方法完成时间 在单线程环境中,类似这样的工作方式: public class TimingInterceptor : SimpleInterceptor { readonly Stopwatch _stopwatch = new Stopwatch(); private bool _isStarted; protected override vo

我正在尝试使用Ninject.Extensions.Interception.dynamicxproxy创建一个拦截器来记录方法完成时间

在单线程环境中,类似这样的工作方式:

public class TimingInterceptor : SimpleInterceptor
{
    readonly Stopwatch _stopwatch = new Stopwatch();
    private bool _isStarted;


    protected override void BeforeInvoke(IInvocation invocation)
    {
        _stopwatch.Restart();
        if (_isStarted) throw new Exception("resetting stopwatch for another invocation => false results");
        _isStarted = true;
        invocation.Proceed();
    }

    protected override void AfterInvoke(IInvocation invocation)
    {
        Debug.WriteLine(_stopwatch.Elapsed);
        _isStarted = false;
    }
}

但是,在多线程场景中,这不起作用,因为秒表是在调用之间共享的。如何将StopWatch实例从BeforeInvoke传递到AfterInvoke,使其不会在调用之间共享

这在多线程应用程序中应该可以正常工作,因为每个线程都应该有自己的对象图。所以,当您开始处理某个任务时,您首先要解析一个新的图形,并且图形不应该从一个线程传递到另一个线程。这允许将什么是线程安全(什么不是)的知识集中到应用程序中连接所有内容的一个地方:线程

当您这样工作时,这意味着当您使用此拦截器来监视单例类(以及跨线程使用的类)时,每个线程仍将获得自己的拦截器(当其注册为瞬态时),因为每次解析时,您都会获得一个新的拦截器(即使您重用相同的“拦截器”实例)

然而,这确实意味着您必须非常小心地将这个被拦截的组件注入到其中,因为如果您将这个被拦截的对象注入到另一个单例中,您将再次遇到麻烦。这种特殊的“麻烦”被称为生活方式不匹配。这很容易让你不小心误解了你的容器,从而给自己带来麻烦,不幸的是Ninject没有可能警告你这一点

但请注意,如果您开始使用decorator而不是拦截器,您的问题将消失,因为使用decorator,您可以将所有内容保存在一个方法中。这意味着即使decorator也可以是单实例,而不会引起任何线程问题。例如:

//命令处理程序的时间交叉关注点
公共类TimingCommandHandlerDecorator:ICommandHandler
{
私有只读ICommandHandler装饰对象;
公共计时CommandHandlerDecorator(ICommandHandler decoratee)
{
this.decoree=decoree;
}
公共无效句柄(TCommand命令)
{
var stopwatch=stopwatch.StartNew();
this.decoree.Handle(命令);
Debug.WriteLine(秒表已过);
}
}

当然,只有在正确地将原则应用于设计时,才可能使用装饰器,因为您通常需要有一些明确的泛型抽象,以便能够将装饰器应用于系统中的大量类。在遗留代码库中高效地使用decorator可能会让我望而生畏。

这在多线程应用程序中应该可以正常工作,因为每个线程都应该有自己的对象图。所以,当您开始处理某个任务时,您首先要解析一个新的图形,并且图形不应该从一个线程传递到另一个线程。这允许将什么是线程安全(什么不是)的知识集中到应用程序中连接所有内容的一个地方:线程

当您这样工作时,这意味着当您使用此拦截器来监视单例类(以及跨线程使用的类)时,每个线程仍将获得自己的拦截器(当其注册为瞬态时),因为每次解析时,您都会获得一个新的拦截器(即使您重用相同的“拦截器”实例)

然而,这确实意味着您必须非常小心地将这个被拦截的组件注入到其中,因为如果您将这个被拦截的对象注入到另一个单例中,您将再次遇到麻烦。这种特殊的“麻烦”被称为生活方式不匹配。这很容易让你不小心误解了你的容器,从而给自己带来麻烦,不幸的是Ninject没有可能警告你这一点

但请注意,如果您开始使用decorator而不是拦截器,您的问题将消失,因为使用decorator,您可以将所有内容保存在一个方法中。这意味着即使decorator也可以是单实例,而不会引起任何线程问题。例如:

//命令处理程序的时间交叉关注点
公共类TimingCommandHandlerDecorator:ICommandHandler
{
私有只读ICommandHandler装饰对象;
公共计时CommandHandlerDecorator(ICommandHandler decoratee)
{
this.decoree=decoree;
}
公共无效句柄(TCommand命令)
{
var stopwatch=stopwatch.StartNew();
this.decoree.Handle(命令);
Debug.WriteLine(秒表已过);
}
}

当然,只有在正确地将原则应用于设计时,才可能使用装饰器,因为您通常需要有一些明确的泛型抽象,以便能够将装饰器应用于系统中的大量类。在遗留代码库中高效地使用decorator可能会让我望而生畏。

这在多线程应用程序中应该可以正常工作,因为每个线程都应该有自己的对象图。所以,当您开始处理某个任务时,您首先要解析一个新的图形,并且图形不应该从一个线程传递到另一个线程。这允许将什么是线程安全(什么不是)的知识集中到应用程序中连接所有内容的一个地方:线程

当您这样工作时,这意味着当您使用此拦截器来监视单例类(以及跨线程使用的类)时,每个线程仍将获得自己的拦截器(当其注册为瞬态时),因为每次解析时,您都会获得一个新的拦截器(即使您重用相同的“拦截器”实例)

然而,这确实意味着您必须非常小心地将这个被拦截的组件注入到何处,因为如果您将这个被拦截的对象注入到另一个对象中