我试图通过代理类拦截一个方法,并得到一个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实例,该实例描述了在此创建的新委托,该实例基于Method是否具有指示应该定时的特定属性:
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]属性修饰的实例。
感谢。
答案 0 :(得分:3)
在您的拦截调用中,您正在创建一个新的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不是新函数的声明类型)。事实上,新函数的声明类型将类似于()_&lt;&gt; ClassSomethingOrOther。