Squeak中的拦截消息

时间:2013-04-12 15:29:17

标签: reflection smalltalk metaclass squeak objc-message-send

我试图理解Smalltalk中更好的反思。我使用的是最新版本的Squeak(v4.3)。我想拦截发送到我的一个类的实例的每个消息。我假设我可以覆盖方法ProtoObject>>withArgs:executeMethod,但是StéphaneDucasse向我解释说,出于性能原因,这个方法没有被使用(这是我自己对他的答案的总结)。我应该覆盖哪种方法/如何拦截已发送的消息?

以下是我的尝试代码:

Object subclass: #C
    instanceVariableNames: 'i'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'CSE3009'.

C class compile: 'newWithi: anInt
    ^(self new) i: anInt ; yourself.'.

C compile: 'withArgs: someArgs executeMethod: aMethod
    Transcript show: ''Caught: ''.
    ^ super withArgs: someArgs executeMethod aMethod.'.

C compile: 'foo: aText
    Transcript show: aText.
    Transcript show: i.
    Transcript cr.'.

C compile: 'i: anInt
    i := anInt.'.

o := C newWithi: 42.
o foo: 'This is foo: '.

执行这整段代码会产生:

This is foo: 42

当我想要:

Caught: This is foo: 42

2 个答案:

答案 0 :(得分:5)

没有内置的方法来拦截这类对象的消息。我们通常使用两种方法来做这种技巧。

首先,您可以创建一个响应doesNotUnderstand:的包装器对象。对于超类,此对象通常为nil,因此它不会从Object继承任何实例方法。 doesNotUnderstand:handler会将其所有消息委托给目标对象。它可以选择在调用之前和之后执行代码。现在,对原始对象的所有引用都将指向新的“代理”对象。对自己的消息不会被截获,代理需要测试返回self的对象,并将返回的对象更改为代理。

第二种方法是使用一种名为Method Wrappers的机制。方法Wrappers允许您使用在调用原始方法之前和之后执行某些其他操作的方法替换一组类中的所有方法。这种方法可以提供相当无缝的结果,并拦截所有消息,包括发送给自己的消息。

MethodWrappers可用于VisualWorks和VASmalltalk。我相信它也适用于Squeak和Pharo,但我并不积极。

答案 1 :(得分:1)

三种主要技术是:

  • 动态代理
  • 方法包装器
  • 字节码仪器

为了更好地比较所有可能的方法,请看看Stephane Ducasse的“Evaluating Message Passing Control Techniques in Smalltalk”(显然你已经认识他了)。

感兴趣的还有F. Rivard的“Smalltalk: A Reflective Langauge”,它展示了如何使用字节码重写来实现前置条件和后置条件。这也是一种拦截形式。