は、次のように上記のコードを呼び出して、我々は...
public class Foo : TreeNode<Foo>
{
}
public class Bar : TreeNode<Foo> // parting from convention
{
}
を書き込むことによって、CRTP規則から逸脱した場合に何が起こるか考えてみましょう...と:
var foo = new Foo();
var foobar = new Bar();
foobar.AddChild(foo);
AddChild
呼び出しがInvalidCastException
をスローしますUnable to cast object of type 'Bar' to type 'Foo'.
CRTPイディオムに関しては、ジェネリック型が宣言子と同じであることタイプです。この言語は、CRTP規約に従わない他のケースをサポートしなければならない。エリック・リッペルト氏は、このトピックに関する素晴らしいブログ記事を投稿しました。彼はこの他のブログからリンクしましたcrtp via c# answer。
あなたはこれに実装を変更した場合、言ったことのすべて
...
public class TreeNode<T> where T : TreeNode<T>
{
public void AddChild(T a_node)
{
a_node.SetParent(this);
}
void SetParent(TreeNode<T> a_parent)
{
m_parent = a_parent;
}
TreeNode<T> m_parent;
}
を...以前InvalidCastException
を投げた上記のコードが動作するようになりました。この変更により、m_Parent
のタイプはTreeNode<T>
となります。 this
いずれかFoo
クラスの場合のようにタイプT
またはTreeNode<Foo>
からBar
継承しているのでBar
クラスの場合TreeNode<T>
のサブクラスを作る - のいずれかの方法は、私たちがSetParent
でキャストを省略し、その不作為によって以来、無効なキャスト例外を回避することができます割り当てはすべてのケースで合法です。これを行うコストは、CRTPの価値の大部分を犠牲にして以前使用されていたように、もはや自由にT
をすべての場所で自由に使用することができません。
私の同僚/友人は、彼が「怒りでそれを使用している」と正直に言うまで、自分自身を言語/言語機能の初心者とみなしています。つまり、彼は、彼が必要とするものを達成する方法がない、そうすることが苦痛であるという不満を感じるだけの言語を十分に知っています。これは非常によく、これらのケースの1つである可能性があります。ここには、generics are not templatesという真実をエコーする制限と相違があります。
私はあなたの例を単純化することができました。同意しない場合は元に戻してください。 – usr
正直言って、これは賢い頭のように見えます。代わりに、構図を使ってツリーを表現する伝統的な方法には何が問題なのですか?これは何をあなたに買うのですか?あまりにも敵対的ではないと思います。私はちょうど興味がある。 – spender
@spender割り当ての数の半分になり、従う必要のある迂回の数が減ります。だから、高性能なコードでは、それは妥当なトレードオフかもしれません。小さな木の場合はおそらく悪い考えです。 – CodesInChaos