AFAIK 答案是否定的,当试图“事后”通知对象类定义更改时,即在实例化/创建之后。
一旦您创建了 S4 类的实例,该对象就会像您创建对象时一样“绑定”到类 def。在我看来,这是完全有道理的。不确定以前缺少的方法(即print_goodbye())的“成功”更新是“偶然”起作用还是实际上是所需的行为。
处理更新的类定义的推荐方法
我的建议:如果您决定想要/需要更新您的类定义,那么重新采购整个项目代码会更安全。这样,您就可以确保在创建实际实例之前一切就绪。我认为其他任何东西都是非常不稳定的基础。
如果你还是决定破解
可能有一些肮脏的方法来破解实际包含类 def 的引用类实例的隐藏 .refClassDef 对象字段(请参阅my_object$.refClassDef)。但是设置这个字段(即在上面使用<-)不起作用:
my_object$.refClassDef <- MyReferenceClass
Error in envRefSetField(x, what, refObjectClass(x), selfEnv, value) :
'.refClassDef' is not a field in class "MyReferenceClass"
也没有通过assign()进行明确分配:
assign(".refClassDef", MyReferenceClass, my_object)
Error in assign(".refClassDef", MyReferenceClass, my_object) :
cannot change value of locked binding for '.refClassDef'
更深入的破解可能涉及查看attributes(my_object$.refClassDef)。
在那里,您可能会找到构成 ref 类 def 的实际部分。但是,我不知道是否即使更改任何内容都会“立即”反映出来。
另外,resetClass() 可能会为您提供更多见解。
更新:2014-03-19
为了处理您的缓存方法,我想到了两种方法:
1。最明显的方式:使用copy()
见?setRefClass
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello")
}
)
)
my_object <- MyReferenceClass$new()
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello_again")
},
print_goodbye = function(){
print("goodbye")
}
)
)
复制前:
my_object$print_hello()
[1] "hello"
复制后:
my_object <- my_object$copy()
my_object$print_hello()
[1] "hello_again"
2。在attributes(my_object$.refClassDef)$refMethods 进行黑客攻击(大纲,尚未运行)
尽管我不建议真正依赖这样的东西,但黑客始终是深入了解事物运作方式的好方法。
在这种情况下,我们可以尝试修改attributes(my_object$.refClassDef)$refMethods,这是一个包含实际方法定义的环境,因为我猜这是调用方法时对象“看起来”的地方。
覆盖实际的方法defs没有问题,但它似乎没有立即生效。我猜有更多“链接”到涉及的“旧”类 def 需要以类似的方式手动更新。
请注意,my_object 仍然具有打印 "hello" 的方法 print_hello:
attributes(my_object$.refClassDef)$refMethods$print_hello
Class method definition for method print_hello()
function ()
{
print("hello")
}
这是覆盖函数的样子:
ensureRecentMethods <- function(obj, classname) {
## Get generator //
gen <- getRefClass(classname)
## Get names of methods belonging to the class of 'obj' //
## This will serve as an index for the update
idx1 <- names(Filter(function(x) {attr(x, "refClassName") == class(obj)},
as.list(attributes(obj$.refClassDef)$refMethods))
)
#idx2 <- names(Filter(function(x) {attr(x, "refClassName")==gen$className},
# as.list(gen$def@refMethods)
#))
## Note:
## 'idx2' could be used to enforce some validity checks such as
## "all old methods must also be present in the updated class def"
## Overwrite //
for (ii in idx1) {
## Note how we are overwriting the old method defs in environment
## 'attributes(obj$.refClassDef)$refMethods' with the updated
## definitions taken from the generator of the updated class
## 'gen$def@refMethods[[ii]]' by making use of the index retrieved
## one step before ('idx1')
expr <- substitute(
assign(x=X, value=VALUE, envir=ENVIR),
list(
X=ii,
VALUE=gen$def@refMethods[[ii]],
ENVIR=attributes(obj$.refClassDef)$refMethods
)
)
eval(expr)
}
## As at the end of the day ref class objects are nothing more than
## environments, there is no need to explicitly return the actual
## ref class object 'obj' as the original object has already
## been updated (pass-by-reference vs. pass-by-value)
return(TRUE)
}
应用它:
ensureRecentMethods(obj=my_object, classname="MyReferenceClass")
即使print_hello 的定义确实被覆盖了,该对象仍然以某种方式获取“旧”版本:
attributes(my_object$.refClassDef)$refMethods$print_hello
## Note the updated method def!
Class method definition for method print_hello()
function ()
{
print("hello_again")
}
my_object$print_hello()
[1] "hello"