Перехват метода с отражением - PullRequest
4 голосов
/ 07 июля 2011

Я пытаюсь перехватить метод через прокси-класс и получаю TargetException «Объект не соответствует целевому типу». Я полагаю, что это похоже на то, что делает фреймворк, подобный PostSharp, но я хочу посмотреть, смогу ли я сделать это сам, как минимум, в качестве упражнения.

Цель в этом случае - рассчитать время вызова метода с помощью Diagnostics.Stopwatch, поместив его в новый делегат. Это становится немного по моей голове, все же.

Вот делегат, который переносит прокси-метод:

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

И затем вот метод, который выполняет перехват, по сути, создавая новый экземпляр MethodInfo, который описывает новый созданный здесь делегат, который основан на том, имеет ли метод определенный атрибут, указывающий, что он должен быть синхронизирован:

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
    }

Теперь мне кажется, я должен быть в состоянии вызвать делегата, который описывает этот объект MethodInfo:

 var interceptor = new FunctionInterceptor();

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

Но я получаю ошибку - объект не соответствует типу цели. Я рассмотрел экземпляр MethodInfo, и DeclaringType - это FunctionInterceptor, то есть я должен передать экземпляр экземпляра перехватчика, как указано выше. Не уверен, в чем проблема.

Если я делаю это, он работает нормально (просто вызывая MethodInfo без переноса):

retVal = method.Invoke( obj, parameters );

Где obj - это экземпляр, объявляющий рассматриваемый метод, который имеет атрибут [Time].

Спасибо.

1 Ответ

3 голосов
/ 07 июля 2011

При вызове Intercept вы создаете новый объект MethodInfo.Этот объект MethodInfo полностью отличается от того, который вы передаете. Он не исходит от класса, который наследует от типа исходного объекта (и не от класса FunctionInterceptor).Если вы вместо этого сделали что-то вроде этого:

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

Это будет работать, потому что метод в этом случае на самом деле происходит от типа прокси.Когда вы вызываете Invoke (перехватчик, параметры), сам метод должен иметь тип FunctionInterceptor.В этом случае это не так (вы можете создать его там, но FunctionInterceptor не является декларирующим типом для новой функции).Фактически объявленный тип для новой функции будет выглядеть примерно так: () _ <> ClassSomethingOrOther.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...