在Common Lisp: Redefine an existing function within a scope?中,提问者询问了类似的问题。但我想创建一个方法专用化程序,而不是函数。基本上,假设已定义了一个方法:
真正的用途是我想创建一个临时环境,在这个环境中,
当然,我尝试过了,但它没有起作用(因为你如何在
有评论吗?
编辑:
Daniel和Terje提供了优秀的链接,扩大了我的知识范围,但我想在去那里之前再深入探索一下更普通的方法。 我一直在研究进入环境时执行add-method,该方法将专门针对eql,并在退出时执行remove-method。 我还没有完成。 如果有人已经尝试过,请发表评论。 将保持线程最新状态。
编辑2:我接近使用add-method方案完成它,但存在问题。 这是我尝试过的内容:
defmethod my-meth ((objA classA) (objB classB)) (...)
我想要做的是(伪代码):
(labels ((my-meth ((objA classA) (objB (eql some-object)))))
do stuff calling my-meth with the object...)
真正的用途是我想创建一个临时环境,在这个环境中,
setf slot-value-using-class
将会在eql
上进行特殊化,从而创建一个特定对象的按需拦截其插槽写入。 (目的是记录旧的和新的插槽值,然后调用下一个方法。)我不想创建一个元类,因为我可能想要拦截已经实例化的标准对象。当然,我尝试过了,但它没有起作用(因为你如何在
LABELS
中进行DEFMETHOD
?),但我想让更有经验的人验证它是否不可行和/或提出合适的方法。有评论吗?
编辑:
Daniel和Terje提供了优秀的链接,扩大了我的知识范围,但我想在去那里之前再深入探索一下更普通的方法。 我一直在研究进入环境时执行add-method,该方法将专门针对eql,并在退出时执行remove-method。 我还没有完成。 如果有人已经尝试过,请发表评论。 将保持线程最新状态。
编辑2:我接近使用add-method方案完成它,但存在问题。 这是我尝试过的内容:
(defun inject-slot-write-interceptor (object fun)
(let* ((gf (fdefinition '(setf sb-mop:slot-value-using-class)))
(mc (sb-mop:generic-function-method-class gf))
(mc-instance (make-instance (class-name mc)
:qualifiers '(:after)
:specializers (list (find-class 't)
(find-class 'SB-PCL::STD-CLASS)
(sb-mop::intern-eql-specializer object)
(find-class 'SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION))
:lambda-list '(new-value class object slot)
:function (compile nil (lambda (new-value class object slot) (funcall fun new-value class object slot))))))
(add-method gf mc-instance)
(defun remove-slot-write-interceptor ()
(remove-method gf mc-instance))
))
(defun my-test (object slot-name data)
(let ((test-data "No results yet")
(gf (fdefinition '(setf sb-mop::slot-value-using-class))))
(labels ((show-applicable-methods () (format t "~%Applicable methods: ~a" (length (sb-mop:compute-applicable-methods gf (list data (class-of object) object (slot-def-from-name (class-of object) slot-name)))))))
(format t "~%Starting test: ~a" test-data)
(show-applicable-methods)
(format t "~%Injecting interceptor.")
(inject-slot-write-interceptor object (compile nil (lambda (a b c d) (setf test-data "SUCCESS !!!!!!!"))))
(show-applicable-methods)
(format t "~%About to write slot.")
(setf (slot-value object slot-name) data)
(format t "~%Wrote slot: ~a" test-data)
(remove-slot-write-interceptor)
(format t "~%Removed interceptor.")
(show-applicable-methods)
)))
当使用对象插槽和数据作为参数调用 (my-test) 时,结果如下:
Starting test: No results yet
Applicable methods: 1
Injecting interceptor.
Applicable methods: 2
About to write slot.
Wrote slot: No results yet <----- Expecting SUCCESS here....
Removed interceptor.
Applicable methods: 1
我卡在这里了。专业化(Specialization)可以使用,因为现在适用的方法包括eql-specialized:after方法,但不幸的是它似乎没有被调用。有人能帮忙吗,这样我就可以完成它并将其重构为一个简单的实用宏了。
change-class
将实例的类更改为带有执行日志记录的“my-meth :around”方法的子类,然后通过改回原始类来禁用日志记录。使用宏编写抽象包装器。 - Terje Norderhaug