代码之家  ›  专栏  ›  技术社区  ›  Tobias Hertkorn

包装现有对象以拦截.NET中的方法/属性调用

  •  2
  • Tobias Hertkorn  · 技术社区  · 16 年前

    我有一种情况,我想拦截对.NET中属性的调用。我一直在城堡里看DynamicProxy,看起来效果不错。但似乎为了使用它,我必须从一个新的对象开始,这意味着我不能这样做:

    MyType myType = new MyType();
    myType.Property = "Test";
    
    ...
    
    MyType wrappedMyType = proxyBuilder.Wrap(myType, new MyInterceptor());
    wrappedMyType.Property = "Test2";
    

    编辑:

    4 回复  |  直到 16 年前
        1
  •  3
  •   Lasse V. Karlsen    16 年前

    这样想吧。让我们考虑搬到中国,在一家中国公司工作,那家公司只会把你的工资支付到一家中国银行的账户上。

    所以,你需要一个中国银行账户。问题是,你想用的银行不会说英语,所以你有问题。

    如果可以的话,你可以做的是调用一个代理服务,一个翻译服务,它代表你调用银行。你对这位代理人说的任何话,都将翻译成中文,并对银行官员说。他/她用中文回答的任何问题都将被翻译成英文,并与您交谈。

    沿通信线路 当和你的银行谈话时。

    然而,这并不能让你的银行官员说英语。

    但如果避开代理对象,则不会有任何更改。

        2
  •  1
  •   jason    16 年前

    virtual 因此,当某个状态来自包装对象,而某个状态来自代理对象时,就会出现不一致的情况。

    举个非常简单的例子:

    abstract class AbstractPerson {
        public int Age { get; protected set; }
        public abstract void Birthday();
    }
    
    class Person : AbstractPerson {
        public Person(int age) { Age = age; }
        public override Birthday() { Age++; }
    }
    

    AbstractPerson 拦截 Birthday .

    class PersonProxy : AbstractPerson {
        readonly AbstractPerson wrappedPerson;
    
        public PersonProxy(AbstractPerson person) { 
            wrappedPerson = person;
        }
        public override void Birthday() {
            DoInterceptors();
            wrappedPerson.Birthday();
        }
        public void DoInterceptors() { 
            // do interceptors 
        }
    }
    

    Age 因为它没有标记为 事实上的

    Person knuth = new Person(71);
    PersonProxy proxy = new PersonProxy(knuth);
    Console.WriteLine(knuth.Age);
    knuth.Birthday();
    Console.WriteLine(knuth.Age);
    Console.WriteLine(proxy.Age);
    

    这将打印

    71
    72
    0
    

    到控制台。怎么了?因为 年龄 未标记为虚拟,我们的代理对象无法重写基本行为并调用 wrappedPerson.Age Age = wrappedPerson.Age PersonProxy

        3
  •  0
  •   user207462    16 年前

    PostSharp 可以 对您有用,具体取决于您想对“拦截”做什么,以及是否可以修改原始代码。

    要使这成为一个可行的选项,您必须能够向要拦截的原始属性添加属性。(我猜这在您的情况下不是一个选项,但不能确定)如果您能够做到这一点,您可以创建一个属性(从OnMethodBoundaryAspect派生),该属性既可以设置“ReturnValue”又可以设置“FlowBehavior”,这样您就可以有效地拦截调用。

        4
  •  0
  •   Justin Long    16 年前

    你可以用系统反射发射.TypeBuilder,但这并不容易,而且可能不适用于所有类型。例如,无法对密封类型执行此操作,因为为了保持正常使用类型的能力,必须在生成的类型中继承该类型,并且必须重写或隐藏基类上的每个属性。除此之外,当重写IL以引发事件或其他事情时,还必须将其发射到属性集方法的主体中。

    所有这些都是可能的,但并不容易,也不完美。你最好换个办法。

    更新:

    推荐文章