Я пытаюсь перехватить метод через прокси-класс и получаю 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].
Спасибо.