块的内部是否可以知道它接收到的选择器并据此评估自己?
Can the inside of a block be aware of the selector it received and evaluate itself based on that?
假设我们在代码中的某个地方有一个块,我们将它分配给一个变量(实例或本地),就像这样。
someName := [ anInstanceVariable doThis. anotherInstanceVariable doThat.]
从外部我想这样使用它:
someName someMessageTheBlockDoesntImplement: argument.
块是否可以作用于特定选择器 someName
并让 anInstanceVariable
或 anotherInstanceVariable
分别执行它和 return 这些对象?
PS。它将充当某种转发器。
您始终可以通过以下方式实现 BlockClosure
class 的 doesNotUnderstand:
:
doesNotUnderstand: aMessage
^ self value: aMessage selector value: aMessage arguments
然后你必须有这样的块:
[ :selector :args |
^ { anInstanceVariable perform: selector withArguments: args.
anotherInstanceVariable perform: selector withArguments: args } ]
但你为什么要做那样的事情?
所有 Smalltalk 方言都允许通过某种方式访问当前上下文。在 VisualWorks 和 Pharo 中,您使用#thisContext。所以如果你有这样的方法......
Object>>someMethod
^[thisContext sender inspect] value
...发送评估:'abc' someMethod ...你会得到一个MethodContext --> ByteString(Object)>>someMethod
或者……
Object>>someMethod: aBlock
^aBlock value
'abc' someMethod: [thisContext sender inspect]
--> 字节串(对象)>>someMethod:
如果您需要查看更多堆栈,您可以使用类似...
| context frames |
context := thisContext.
frames := OrderedCollection new.
[context isNil or: [context stack isNil]] whileFalse: [
frames add: context.
context := context sender].
^frames
在 VA Smalltalk 中,您可以编写...
someMethod
^[Processor activeProcess currentFrame context inspect] value
...一个 BlockContextTemplate --> [] in Object>>#someMethod
查看调试器代码是了解您可以使用哪些其他技术的好方法。
这个问题相当混乱。首先,我猜你的意思是 "the selector someMessageTheBlockDoesntImplement:" 而不是 "someName"。但是你基本上要求的是能够制作转发代理。
您通常不使用 BlockClosures 来执行此操作,而是创建一个 class MyForwarder,它继承 Object 甚至 ProtoObject(取决于您使用的 Smalltalk 以及您希望转发器的透明度)。
在此 class 中添加您的两个实例变量,以便您可以保存它们和一些方法,以便您可以设置它们等。
然后你在 MyForward 中实现 #doesNotUnderstand:
看起来像这样:
doesNotUnderstand: aMessage
aMessage selector == #thisMessageGoesToFirstGuy
ifTrue: [
^ firstGuy perform: aMessage selector withArguments: aMessage arguments ]
ifFalse: [
^ secondGuy perform: aMessage selector withArguments: aMessage arguments ]
代码未经测试,但您明白了。
假设我们在代码中的某个地方有一个块,我们将它分配给一个变量(实例或本地),就像这样。
someName := [ anInstanceVariable doThis. anotherInstanceVariable doThat.]
从外部我想这样使用它:
someName someMessageTheBlockDoesntImplement: argument.
块是否可以作用于特定选择器 someName
并让 anInstanceVariable
或 anotherInstanceVariable
分别执行它和 return 这些对象?
PS。它将充当某种转发器。
您始终可以通过以下方式实现 BlockClosure
class 的 doesNotUnderstand:
:
doesNotUnderstand: aMessage
^ self value: aMessage selector value: aMessage arguments
然后你必须有这样的块:
[ :selector :args |
^ { anInstanceVariable perform: selector withArguments: args.
anotherInstanceVariable perform: selector withArguments: args } ]
但你为什么要做那样的事情?
所有 Smalltalk 方言都允许通过某种方式访问当前上下文。在 VisualWorks 和 Pharo 中,您使用#thisContext。所以如果你有这样的方法......
Object>>someMethod
^[thisContext sender inspect] value
...发送评估:'abc' someMethod ...你会得到一个MethodContext --> ByteString(Object)>>someMethod
或者……
Object>>someMethod: aBlock
^aBlock value
'abc' someMethod: [thisContext sender inspect]
--> 字节串(对象)>>someMethod:
如果您需要查看更多堆栈,您可以使用类似...
| context frames |
context := thisContext.
frames := OrderedCollection new.
[context isNil or: [context stack isNil]] whileFalse: [
frames add: context.
context := context sender].
^frames
在 VA Smalltalk 中,您可以编写...
someMethod
^[Processor activeProcess currentFrame context inspect] value
...一个 BlockContextTemplate --> [] in Object>>#someMethod
查看调试器代码是了解您可以使用哪些其他技术的好方法。
这个问题相当混乱。首先,我猜你的意思是 "the selector someMessageTheBlockDoesntImplement:" 而不是 "someName"。但是你基本上要求的是能够制作转发代理。
您通常不使用 BlockClosures 来执行此操作,而是创建一个 class MyForwarder,它继承 Object 甚至 ProtoObject(取决于您使用的 Smalltalk 以及您希望转发器的透明度)。
在此 class 中添加您的两个实例变量,以便您可以保存它们和一些方法,以便您可以设置它们等。
然后你在 MyForward 中实现 #doesNotUnderstand:
看起来像这样:
doesNotUnderstand: aMessage
aMessage selector == #thisMessageGoesToFirstGuy
ifTrue: [
^ firstGuy perform: aMessage selector withArguments: aMessage arguments ]
ifFalse: [
^ secondGuy perform: aMessage selector withArguments: aMessage arguments ]
代码未经测试,但您明白了。