C# 使用反射截获方法调用或属性更改
我正在尝试创建一个泛型类,它将在调用方法或访问或更改属性时触发事件。它也可能会触发事件以响应其他更改或正在采取的操作,但目前仅此而已 为了做到这一点,我想拦截每个方法调用和每个属性访问/更改,但我无法确切知道我正在处理哪些方法。没有给定的接口定义我将使用的每个泛型类型C# 使用反射截获方法调用或属性更改,c#,.net,oop,generics,aop,C#,.net,Oop,Generics,Aop,我正在尝试创建一个泛型类,它将在调用方法或访问或更改属性时触发事件。它也可能会触发事件以响应其他更改或正在采取的操作,但目前仅此而已 为了做到这一点,我想拦截每个方法调用和每个属性访问/更改,但我无法确切知道我正在处理哪些方法。没有给定的接口定义我将使用的每个泛型类型T,因此我必须使用反射。下面是我的设想(Trigger是类,而generic将是T类型): 我意识到我把问题过分简化了。首先,我必须处理参数。其次,您不能像那样以编程方式重写一个方法。第三,我还没有开始研究房地产。另外,我必须只更改
T
,因此我必须使用反射。下面是我的设想(Trigger
是类,而generic
将是T
类型):
我意识到我把问题过分简化了。首先,我必须处理参数。其次,您不能像那样以编程方式重写一个方法。第三,我还没有开始研究房地产。另外,我必须只更改对象的这些内容,而不是整个类型,所以我也不确定这是如何工作的
我已经做了研究,发现所有的内容都很混乱。我意识到我应该以某种方式使用AOP,但除了OOP和过程编程之外,我从未做过任何事情,所以我相当迷失在这密集的知识丛林中。听起来我需要使用PostSharp或Unity,但我仍然不知道如何使用after、and、and和(每个单词都有单独的链接)
有没有更简单的方法?我甚至可以在不使用接口或预定义类的情况下完成它吗
是泛型让我的问题变得特别复杂。如果我可以让一个类继承自
T
,然后使用代理来捕获它的方法调用和属性访问/更改,那么事情可能会简单一些,尽管我仍然缺乏对AOP的基本理解。如果您能提供任何帮助,我们将不胜感激。如果可能的话,请以初学者的水平写下你的答案(尽管我对OOP非常了解,就像我说的,我对AOP一无所知)。你可以使用一个新的开源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();
}
公共类触发器:方面
{
静态公共事件EventArgs MethodCalled;
静态私有触发器m_Singleton=新触发器();
//自动织造方面
静态触发器()
{
Aspect.Weave(method=>method.ReflectedType==typeof(T));
}
公共IEnumerable建议(MethodInfo方法)
{
//定义仅在方法执行未失败时触发的通知
收益返回建议.Basic.After.Returning(()=>
{
if(MethodCalled!=null)
{
MethodCalled(this,null);
}
});
}
}
公共A类
{
公开无效测试()
{
}
}
int main(字符串[]args)
{
触发
NConcern AOP框架是一个运行时工作的轻型框架。它通过继承避免工厂/代理,使用代码注入。它允许您通过注入可以使用简单委托、ILGenerator或表达式树(linq)创建的代码来向类添加方面方法之前/之后或周围。它可以处理密封类、密封方法、虚拟方法或显式/隐式接口实现
在我的示例中,我创建了一个从方面派生的类(抽象类)
当类从方面派生时,它必须通过返回Advice实例(Before/After/After.returning/After.Throwing或about)来实现Advice方法。每个类都可以使用委托或表达式来创建,以定义在方法截取时需要执行的操作
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));
}
}
}
公共类MyAspect:IAspect
{
//最初调用此方法(不是在拦截时)重写方法体。
公共IEnumerable建议(MethodInfo方法)
{
//这段代码意味着该方法将被重写,以便在仅用于公共方法的原始代码之前,将方法名写入控制台
如果(方法IsPublic)
{
返回Advice.Basic.Before(()=>Console.WriteLine(method.Name));
}
}
}
用法
//将myaspect附加到类。将传递一个类的所有方法以建议方法处理重写方法。
Aspect.Weave(method=>method.ReflectedType==typeof(A));
//从类中分离myaspect。将重写所有方法以返回原始代码。
发布(method=>method.ReflectedType==typeof(A));
无需借助使用post-bulid IL-weaving的完整AOP框架,您就可以使用Castle并创建拦截器。您可以在网上找到大量教程:
为了让拦截器工作,您需要确保泛型类的方法和属性是虚拟的。这允许DynamicProxy的运行时编织代码生成一个包装类的代理。我研究了一点这个问题,发现它涉及到代码编织。代码编织正在改变事情,以便调用o任何方法首先都会被重新路由到其他编织的代码来完成它。Spring.NET已经做到了这一点。因此,如果你真的想继续编写你自己的方法,你应该研究已经做到这一点的开源项目来学习。@JohnPeters我不想编写我自己的框架或代理。我想做的就是——就像前面的术语一样m AOP说,正如我通过Spring.NET学到的(谢谢)--是让我的Trigger
类充当顾问。它将在方法返回后向从T
类型的内部对象调用的所有方法提供建议,每个Trigger
对象都将包含该类,该类使用方法信息从Trigger
触发事件(与属性相同,无论是获取还是设置属性),或者类似的东西。不过,再一次,我不知道从哪里开始,即使在阅读了AOP之后。
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));