Method interception with reflection

I try to intercept a method through a proxy class and get a TargetException "Object does not match target type". I find this to be similar to what a structure like PostSharp does, but I want to see if I can do it myself as an exercise, at least.

The goal in this case is to call the method using Diagnostics.Stopwatch by transferring it to a new delegate. However, this is a bit compared to my head.

Here is the delegate that wraps the proxy method:

public static Func<Object> Time(this MethodInfo target, object parent, object[] parameters, Action<string> logger) { return delegate { Stopwatch s = new Stopwatch(); s.Start(); object value = target.Invoke(parent, parameters); s.Stop(); logger("Elapsed ms for function '" + target.Name + "' = " + s.ElapsedMilliseconds.ToString()); return value; }; } 

And here is the method that performs the interception, essentially creating a new instance of MethodInfo, which describes the new delegate created here, which is based on whether the method has a specific attribute indicating that it should be synchronized:

 public class FunctionInterceptor { public MethodInfo Intercept(Object proxy, MethodInfo method, Object[] args) { return new Func<Object>(() => { var data = method.GetCustomAttributes(typeof(TimeAttribute), true); object result = default(object); foreach (object d in data) { if (d.GetType() == typeof(TimeAttribute)) // [Time] attribute { result = method.Time(proxy, args, Log.Write).DynamicInvoke(args); } } return result; }).Method; // returning MethodInfo of this delegate } 

Now it seems to me that I should be able to call the delegate that describes this MethodInfo object:

  var interceptor = new FunctionInterceptor(); retVal = interceptor.Intercept(proxy, method, parameters).Invoke(interceptor, parameters); 

But I get an error. The object does not match the type of target. I looked at an instance of MethodInfo, and DeclaringType is a FunctionInterceptor, that is, I have to pass an instance of the interceptor as described above. I don’t know what the problem is.

If I do this, it works fine (just calling MethodInfo without wrapping it):

 retVal = method.Invoke( obj, parameters ); 

Where obj is an instance declaring the method in question, one that is decorated with the [Time] attribute.

Thanks.

+4
source share
1 answer

In your Intercept call, you create a new MethodInfo object. This MethodInfo object is completely different from the one you are passing. It does not come from a class that inherits from the type of the source object (and not from the FunctionInterceptor class). If you did something like this:

 public object Intercept(object proxy, MethodInfo method, object[] args) { var data = method.GetCustomAttributes(typeof(TimeAttribute), true); object result = default(object); foreach (object d in data) { if (d.GetType() == typeof(TimeAttribute)) // [Time] attribute { result = method.Time(proxy, args, Log.Write).DynamicInvoke(args); } } return result; } 

This will work because the method in this case actually comes from the proxy type. When you call Invoke (interceptor, parameters), the method itself must be of type FunctionInterceptor. In this case, this is not the case (you can create it there, but the FunctionInterceptor is not a declaring type for the new function). In fact, the declaration type for the new function will look like () _ <> ClassSomethingOrOther.

+3
source

All Articles