开发者

Intercepting a method with reflection

I am trying to intercept a method through a proxy class and am getting a TargetException "Object does not match target type". I believe this is similar to what a framework like PostSharp does, but I want to see if I can do this myself as an excercise at the very least.

The goal in this case is to time the method call using Diagnostics.Stopwatch by wrapping it in a new delegate. Its getting a bit over my head, though.

Here is the delegate which wraps the proxied 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 then here is a method which does the interception, essentially creating a new MethodInfo instance that describes the new delegate created here, which is based on whether the Me开发者_运维百科thod has a certain attribute indicating it should be timed:

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 I should be able to invoke the delegate that this MethodInfo object describes:

 var interceptor = new FunctionInterceptor();

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

But I am getting the error - Object does not match target type. I examined the MethodInfo instance and the DeclaringType is FunctionInterceptor, meaning I should be passing in the instance of the interceptor as above. Not sure what the problem is.

If I do this it works fine (just invoking the MethodInfo without wrapping it):

retVal = method.Invoke( obj, parameters );

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

Thanks.


In your Intercept call, you're creating a new MethodInfo object. That MethodInfo object is completely different from the one that you pass in. It does not come from a class that inherits from the type of the original object (nor does it come from the FunctionInterceptor class). If you instead 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;
}

It will work because the method in this case actually comes from the proxy's type. When you call Invoke(interceptor,parameters), the method itself has to be from the type FunctionInterceptor. In this case it is not (you may create it there but FunctionInterceptor is not the declaring type for the new function). In fact the declaring type for the new function is going to be something like ()_<>ClassSomethingOrOther.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜