6

我在拦截教程中已经注意到你可以定位一个方法并拦截它。即Ninject带参数的方法级拦截

Kernel.Bind<Foo>().ToSelf(); 
Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(), invocation => {}); 

文档/教程并没有什么的情况下做到这一点你试图拦截该方法具有参数即如果 ThrowsAnError接受一个字符串作为参数。

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

在结合我没有访问PARAMS,所以我在想,我是否要对这个错误的方式的时候?

编辑

Working example

回答

3

我想你是误会发生了什么。您的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); 
    } 
} 

换句话说,当解析的Foo被调用时提供的参数将被传递给装饰实例。然而,尽管有拦截,但这是间接(更慢)的一点,但概念是一样的。我必须承认我不熟悉Ninject拦截,但在invocation对象上可能有Proceed方法。换句话说,你应该做这样的事情:

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); 
     } 
    }); 

UPDATE

我假设InterceptReplace<T>方法的第一个参数是不是代表,而是一个表达式树,如Expression<Action<T>>。这个方法实际上并没有被调用,但是它被分析以找出要拦截的方法。换句话说,由于该方法从未被调用过,所以你可以提供任何你自己的参数。诀窍是让C#编译器知道使用哪种方法重载(如果有的话)。你提供垃圾无关紧要。当两个参数都是引用类型,这可能会工作:

Kernel.InterceptReplace<Foo>(foo => foo.ThrowsAnError(null, null), 
+1

我看你是从哪里来的,但我觉得OP将有一个问题,因为绑定到方法'Kernel.InterceptReplace (富=> foo.ThrowsAnError(),...);'会需要在那里输入参数,否则它不会编译,因为ThrowsAnError需要N个参数,在你的实例中,你将不得不像这样绑定。 'Kernel.InterceptReplace (foo => foo.ThrowsAnError(somehowSatisfyParam1,somehowSatisfyParam2),...);'虽然我可能是错的。 – Grofit

+1

Grofit是正确的,'foo.ThrowsAnError()'仍然需要params来规定 –

+1

@MarkWalsh:啊,我明白了。查看我的更新。 – Steven