我试图创建一个泛型类,只要调用方法或访问或更改属性,就会触发事件。它也可能会针对正在采取的其他变化或行动触发事件,但就目前而言,它就是它。
为了做到这一点,我想拦截每个方法调用和每个属性访问/更改,但我无法确切知道我正在处理哪些方法。没有给定的界面定义了我正在使用的每个泛型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或Unity,但我仍然不清楚looking at all this和this之后的情况,these two,以及this(所有单独的链接,每个字)。
有没有更简单的方法呢?我甚至可以在不使用接口或预定义类的情况下完成它吗?
它的泛型使我的问题特别复杂。如果我可以让一个类继承自T
,然后使用代理来捕获它的方法调用和属性访问/更改,那么事情可能会更简单一些,尽管我仍然缺乏对AOP的基本理解去做。您可以提供的任何帮助将不胜感激。如果可能的话,请在初级阶段写下你的答案(虽然我非常了解我的OOP,就像我说的,我不知道关于AOP的第一件事)。
答案 0 :(得分:0)
你可以使用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();
}
您可以在此处找到类似的示例代码来源:Example of observation pattern implemented with 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));
答案 1 :(得分:0)
如果不使用使用post-bulid IL编织的全面AOP框架,您可以使用Castle DynamicProxy并创建拦截器。你可以在网上找到很多教程:
要使拦截器正常工作,您需要确保您的通用类的方法和属性为virtual
。这允许DynamicProxy的运行时编织代码生成包装您的类的代理。