简体   繁体   English

拦截方法调用或带反射的属性更改

[英]Intercept Method Invocation or Property Change with Reflection

I'm trying to create a generic class that will fire an event whenever a method is called or a property is accessed or changed. 我正在尝试创建一个泛型类,无论何时调用方法或访问或更改属性,都会触发事件。 It may also fire events in response to other changes or actions being taken, but for now, that'll be it. 它也可能会响应其他更改或采取的措施触发事件,但就目前而言。

In order to do so, I'd like to intercept every method call and every property access/change, but I have no way of knowing exactly which methods I'm handling. 为了做到这一点,我想拦截每个方法调用和每个属性访问/更改,但我无法确切知道我正在处理哪些方法。 There's no given interface that defines every generic type T I'll be working with, so I have to use reflection. 没有给定的接口定义将要使用的每个泛型T ,因此必须使用反射。 Here's how I envision it ( Trigger<T> is the class, and generic would be of type T ): 这是我设想的方式( Trigger<T>是类, genericT类型):

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*/);
            };
    }
}

I realize that I've grossly oversimplified the problem. 我意识到我已经大大简化了这个问题。 First off, I'd have to deal with parameters. 首先,我必须处理参数。 Second, you can't just override a method programmatically like that. 其次,你不能像这样以编程方式覆盖方法。 And third, I haven't even started on properties yet. 第三,我什至还没有开始研究房地产。 Plus, I'd have to be changing these things for only the object, not the entire type, so I'm not sure how that works either. 另外,我必须只为对象改变这些东西,而不是整个类型,所以我不确定它是如何工作的。

I've done my research, and all I find is confusing content. 我已经完成了我的研究,而且我发现所有内容都令人困惑。 I realize that I'm somehow supposed to be using AOP, but I've never done anything other than OOP and procedural programming, so I'm rather lost in this dense jungle of knowledge. 我意识到我在某种程度上应该使用AOP,但我从未做过OOP和程序编程之外的任何事情,所以我宁愿迷失在这个密集的知识丛林中。 It sounds like I'll need to use PostSharp or Unity, but I still have no clue how after looking at all this , and this , and these two , and also this (all separate links, per word). 这听起来像我需要使用PostSharp或统一,但我仍然不知道以后怎么 所有 ,和 2 ,也是这个 (所有单独的环节,每个字)。

Is there any simpler way to do this? 有没有更简单的方法来做到这一点? And can I even do it without using interfaces or predefined classes? 我什至可以在不使用接口或预定义类的情况下做到这一点?

It's generics that make my problem particularly complicated. 这是泛型,使我的问题特别复杂。 If I could just have a class inherit from T , and then use a proxy to capture its method calls and property accesses/changes, then things would maybe be a tad simpler, though I still lack the fundamental understanding of AOP to do that. 如果我可以让一个类继承自T ,然后使用代理来捕获它的方法调用和属性访问/更改,那么事情可能会更简单一些,尽管我仍然缺乏对AOP的基本理解。 Any help you can provide would be much appreciated. 您可以提供的任何帮助将不胜感激。 If possible, please write your answer at a beginner level (though I know my OOP fairly strongly, like I said, I don't know the first thing about AOP). 如果可能的话,请在初级阶段写下你的答案(虽然我非常了解我的OOP,就像我说的,我不知道关于AOP的第一件事)。

You can do it like that using NConcern , a new open source AOP Framework on which I actively work. 您可以使用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();
}

You can find a similar Example code source here : Example of observation pattern implemented with NConcern 您可以在此处找到类似的示例代码源: 使用NConcern实现的观察模式示例

NConcern AOP Framework is a light framework working at runtime. NConcern AOP Framework是在运行时工作的轻型框架。 It work with code injection avoiding factory/proxy by inheritance. 它与代码注入一起工作,通过继承避免了工厂/代理。 It allow you to add aspect to a class by injecting code you can create using simple delegate, ILGenerator or expression tree (linq) before/after or around a method. 它允许您通过在方法之前/之后或周围注入可使用简单委托,ILGenerator或表达式树(linq)创建的代码来向类中添加方面。 It can handle sealed class, sealed method, virtual method or explicit/implicit interface implementation. 它可以处理密封类,密封方法,虚拟方法或显式/隐式接口实现。

Into my example, I create a class derived from Aspect (abstract class). 在我的示例中,我创建了一个从Aspect派生的类(抽象类)。

When a class derived from Aspect, it have to implement Advise method by returning an instance of Advice (Before/After/After.Returning/After.Throwing or Around). 当一个类从Aspect派生时,它必须通过返回一个Advice实例(Before / After / After.Returning / After.Throwing或Around)来实现Advise方法。 Each can be created with Delegate or Expression to define what you need to do on method interception. 每个都可以使用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));
        }
    }
}

Usage 用法

//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));

Without resorting to a full-on AOP framework that uses post-bulid IL weaving, you can use Castle's DynamicProxy and create an interceptor. 无需诉诸使用后编织IL编织的完整AOP框架,您可以使用Castle的DynamicProxy并创建拦截器。 You can find plenty of tutorials online: 你可以在网上找到很多教程:

For your interceptor to work, you will need to make sure your generic class's methods and properties are virtual . 为了使拦截器正常工作,您需要确保通用类的方法和属性是virtual This allows the DynamicProxy's runtime weaving code to generate a proxy that wraps your class. 这允许DynamicProxy的运行时编织代码生成包装您的类的代理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM