[英]Intercept Method Invocation or Property Change with Reflection
我正在尝试创建一个泛型类,无论何时调用方法或访问或更改属性,都会触发事件。 它也可能会响应其他更改或采取的措施触发事件,但就目前而言。
为了做到这一点,我想拦截每个方法调用和每个属性访问/更改,但我无法确切知道我正在处理哪些方法。 没有给定的接口定义将要使用的每个泛型T
,因此必须使用反射。 这是我设想的方式( Trigger<T>
是类, generic
是T
类型):
public Trigger()
{
this.generic = default(T);
foreach (MethodInfo m in generic.GetType().GetMethods())
{
// This is pseudocode, since I can't just set MethodInfo to a new method
m = delegate()
{
m.Invoke(this.generic, null);
if (MethodCalled != null)
MethodCalled(this, eventArgs /*imagine these are valid EventArgs*/);
};
}
}
我意识到我已经大大简化了这个问题。 首先,我必须处理参数。 其次,你不能像这样以编程方式覆盖方法。 第三,我什至还没有开始研究房地产。 另外,我必须只为对象改变这些东西,而不是整个类型,所以我不确定它是如何工作的。
我已经完成了我的研究,而且我发现所有内容都令人困惑。 我意识到我在某种程度上应该使用AOP,但我从未做过OOP和程序编程之外的任何事情,所以我宁愿迷失在这个密集的知识丛林中。 这听起来像我需要使用PostSharp或统一,但我仍然不知道以后怎么找 在 所有 这 ,和这和这 2 ,也是这个 (所有单独的环节,每个字)。
有没有更简单的方法来做到这一点? 我什至可以在不使用接口或预定义类的情况下做到这一点?
这是泛型,使我的问题特别复杂。 如果我可以让一个类继承自T
,然后使用代理来捕获它的方法调用和属性访问/更改,那么事情可能会更简单一些,尽管我仍然缺乏对AOP的基本理解。 您可以提供的任何帮助将不胜感激。 如果可能的话,请在初级阶段写下你的答案(虽然我非常了解我的OOP,就像我说的,我不知道关于AOP的第一件事)。
您可以使用NConcern做到这一点, NConcern是我积极工作的新开源AOP框架。
public class Trigger<T> : Aspect
{
static public event EventArgs MethodCalled;
static private Trigger<T> m_Singleton = new Trigger<T>();
//Auto weaving aspect
static Trigger()
{
Aspect.Weave<Trigger<T>>(method => method.ReflectedType == typeof(T));
}
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//define an advice to trigger only when method execution not failed
yield return Advice.Basic.After.Returning(() =>
{
if (MethodCalled != null)
{
MethodCalled(this, null);
}
});
}
}
public class A
{
public void Test()
{
}
}
int main(string[] args)
{
Trigger<A>.MethodCalled += ...
new A().Test();
}
您可以在此处找到类似的示例代码源: 使用NConcern实现的观察模式示例
NConcern AOP Framework是在运行时工作的轻型框架。 它与代码注入一起工作,通过继承避免了工厂/代理。 它允许您通过在方法之前/之后或周围注入可使用简单委托,ILGenerator或表达式树(linq)创建的代码来向类中添加方面。 它可以处理密封类,密封方法,虚拟方法或显式/隐式接口实现。
在我的示例中,我创建了一个从Aspect派生的类(抽象类)。
当一个类从Aspect派生时,它必须通过返回一个Advice实例(Before / After / After.Returning / After.Throwing或Around)来实现Advise方法。 每个都可以使用Delegate或Expression创建,以定义您在方法拦截时需要执行的操作。
public class MyAspect : IAspect
{
//this method is called initially (not on interception) to rewrite method body.
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//this block of code means that method will be rewrite to execute a write method name to console before original code only for public methods
if (method.IsPublic)
{
yield return Advice.Basic.Before(() => Console.WriteLine(method.Name));
}
}
}
用法
//attach myaspect to A class. All methods of A will be passed to Advise method to process methods rewriting.
Aspect.Weave<MyAspect>(method => method.ReflectedType == typeof(A));
//detach myaspect from A class. All methods will be rewrite to give back original code.
Aspect.Release<MyAspect>(method => method.ReflectedType == typeof(A));
无需诉诸使用后编织IL编织的完整AOP框架,您可以使用Castle的DynamicProxy并创建拦截器。 你可以在网上找到很多教程:
为了使拦截器正常工作,您需要确保通用类的方法和属性是virtual
。 这允许DynamicProxy的运行时编织代码生成包装您的类的代理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.