Squeak中的拦截消息

Yan*_*euc 5 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: '.
Run Code Online (Sandbox Code Playgroud)

执行这整段代码会产生:

This is foo: 42
Run Code Online (Sandbox Code Playgroud)

当我想要:

Caught: This is foo: 42
Run Code Online (Sandbox Code Playgroud)

Dav*_*uck 5

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

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

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

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