2012-08-24 6 views
7

thisに関連していますが、若干異なります。S3オブジェクトのS3スタイルのディスパッチは、正式なメソッド定義を使用して

私は、S4クラスとS3クラスの両方でメソッドを正式に登録する方法を探していますが、ディスパッチのためのひどいS3-dot-naming-schemeに頼ることはありません。例:

setClass("foo"); 
setClass("bar"); 

setGeneric("test", function(x, ...){ 
    standardGeneric("test"); 
}); 

setMethod("test", "bar", function(x, ...){ 
    return("success (bar)."); 
}); 

obj1 <- 123; 
class(obj1) <- "bar"; 
test(obj1); 

この例では、我々は素晴らしいです機能test.barを、名前を付ける必要がなく、クラスbarのS3オブジェクトに対してtestメソッドを登録する方法を示しています。ただし、この方法で登録すると、オブジェクトの最初のS3クラスにのみディスパッチされます。例えば:S4メソッドのディスパッチが唯一のクラスfooとそのスーパークラスを尽くしますので

obj2 <- 123; 
class(obj2) <- c("foo", "bar"); 
test(obj2); 

これは、動作しません。 fooの適切なメソッドが見つからない場合、bartestメソッドが自動的に選択されるように、この例をどのように拡張できますか?例えば。 S3スタイルのディスパッチがありますが、すべての名前付けに戻る必要はありませんtest.footest.bar

要約:正式なメソッドディスパッチを使用するジェネリック関数を作成する方法ですが、さらに複数のクラスを持つS3オブジェクトのオブジェクトの第2、第3などのクラスにフォールバックします。

setOldClass(c("foo", "bar")) 

setGeneric("test", function(x, ...)standardGeneric("test")) 
setMethod("test", "bar", function(x, ...)return("success (bar).")) 

答えて

2

あなたは方法

test = function(x, ...) UseMethod("test") 

setGeneric("test") 

.redispatch = function(x, ...) 
{ 
    if (is.object(x) && !isS4(x) && length(class(x)) != 1L) { 
     class(x) = class(x)[-1] 
     callGeneric(x, ...) 
    } else callNextMethod(x, ...) 
} 

setMethod(test, "ANY", .redispatch) 

を書くことができしかし、私は個人的に、このようにS3およびS4を混在させないでしょう。

+0

はい私は似たようなことをしています。しかし実際には、xのクラス属性を途中で実際に変更しているということは、望ましくない副作用を伴う可能性があります。オブジェクト自体を変更せずに次のメソッドにディスパッチできる方法はありますか? – Jeroen

+0

私はあなたに答えがありません。私はS3クラス 'bar'で動作する 'bar'のS4メソッドは実装の事故であり、非常に不安定な基盤上で複雑な構造を構築していると思います。 –

3

?setOldClassは答えを与えます。

+0

これはまさに私が望むものではありません。これは、クラス "foo"と "bar"の間の正式な継承を必要とします。クラス= [x、 "bar"] x =任意の任意のオブジェクトに対して、xとbarの間の継承をすべてのクラスxに対して宣言することなく、それを動作させたい。他の誰かがクラス["zoo"、 "bar"]でオブジェクトを作成したとすると、 'test()'関数は "bar"のメソッドを選択するのに十分スマートでなければなりません。 – Jeroen

関連する問題