5

我试图更好地理解 Smalltalk 中的反射。我正在使用最新版本的 Squeak (v4.3)。我想拦截发送到我的一个类的实例的每条消息。我以为我可以重写该方法ProtoObject>>withArgs:executeMethod,但 Stéphane Ducasse 向我解释说,出于性能原因,不使用此方法(这是我自己对他的回答的总结)。我应该覆盖哪种方法/如何拦截发送的消息?

这是我尝试的代码:

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
4

2 回答 2

5

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

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

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

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

于 2013-04-12T15:47:53.070 回答
1

三种主要技术是:

  • 动态代理
  • 方法包装
  • 字节码检测

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

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

于 2013-04-17T06:17:12.083 回答