Ninject方法级别拦截与参数

Mar*_*lsh 7 c# dependency-injection ninject ninject-extensions ninject-interception

我已经注意到在截取教程中你可以定位一个方法并拦截它.即

 Kernel.Bind<Foo>().ToSelf();
 Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(), invocation => {} );
Run Code Online (Sandbox Code Playgroud)

文档/教程没有介绍在您尝试拦截的方法具有参数的实例中要执行的操作,即ThrowsAnError是否接受字符串作为参数.

 Kernel.Bind<Foo>().ToSelf();
 Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(**param goes here**), invocation => {} );
Run Code Online (Sandbox Code Playgroud)

在绑定时我无法访问params,所以我想知道我是否会以错误的方式进行此操作?

编辑

工作实例

Ste*_*ven 4

我认为你误解了发生的事情。您的Foo对象将被替换为包含拦截器的装饰器。这是一个简单的例子:

public class FooDecorator : Foo
{
    private readonly Foo decorated;

    public FooDecorator(Foo foo) { this.decorated = foo; }

    public void ThrowsAnError(object param1, int param2)
    {
        // calls the decorated instance with supplied parameters
        this.decorated.ThrowsAnError(param1, param2);
    }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,调用解析的 Foo 时提供的参数将被传递给装饰实例。

然而,对于拦截来说,这一切都更加间接(并且速度更慢),但概念是相同的。我必须承认我对 Ninject 拦截并不熟悉,但是对象Proceed上可能有一个方法invocation。换句话说,你应该这样做:

Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(),
    invocation =>
    {
        try
        {
            // calls the decorated instance with supplied parameters
            invocation.Proceed();
        }
        catch (Exception ex)
        {
            Kernel.Get<ILogger>().Log(ex);
        }
    } );
Run Code Online (Sandbox Code Playgroud)

更新

我假设该InterceptReplace<T>方法的第一个参数不是委托,而是表达式树,例如Expression<Action<T>>. 这个方法其实并没有被调用,只是分析一下要拦截哪个方法。换句话说,由于该方法从未被调用,因此您可以只提供任何参数。诀窍是让 C# 编译器知道要使用哪个方法重载(如果有)。如果你提供垃圾也没关系。当两个参数都是引用类型时,这可能会起作用:

Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(null, null),
Run Code Online (Sandbox Code Playgroud)

  • 史蒂文,您关于参数传递的说法是正确的,请参阅我的编辑和工作测试版本。 (2认同)