considerare che cosa succede se ci si discosta da CRTP convenzione scrivendo ...
public class Foo : TreeNode<Foo>
{
}
public class Bar : TreeNode<Foo> // parting from convention
{
}
... e quindi chiamare il codice precedente come segue:
var foo = new Foo();
var foobar = new Bar();
foobar.AddChild(foo);
La chiamata AddChild
genera InvalidCastException
dicendo Unable to cast object of type 'Bar' to type 'Foo'.
Per quanto riguarda l'idioma CRTP - è solo convenzione che richiede che il tipo generico sia lo stesso del dichiar tipo. La lingua deve supportare gli altri casi in cui la convenzione CRTP non viene seguita. Eric Lippert ha scritto un ottimo post sul blog su questo argomento, che ha collegato da questo altro crtp via c# answer.
Tutto ciò detto, se si cambia l'attuazione a questa ...
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;
}
... il codice di cui sopra, che in precedenza ha gettato il InvalidCastException
ora funziona.La modifica rende m_Parent
un tipo di TreeNode<T>
; rendendo this
sia il tipo di T
come nel caso Foo
class' o una sottoclasse di TreeNode<T>
nel caso Bar
classe dal Bar
eredita da TreeNode<Foo>
- in entrambi i casi ci consente di omettere il cast in SetParent
e tale omissione evitare l'eccezione getto valido in quanto la l'assegnazione è legale in tutti i casi. Il costo di questa operazione non è più possibile utilizzare liberamente T
in tutti i luoghi poiché era stato precedentemente utilizzato, il che sacrifica gran parte del valore di CRTP.
Un mio collega/amico si considera un novizio di una lingua/lingua fino a quando non può onestamente dire di essere "usato con rabbia"; cioè, conosce la lingua abbastanza bene da essere frustrato che non c'è modo di realizzare ciò di cui ha bisogno o che farlo è doloroso. Questo molto bene potrebbe essere uno di quei casi, in quanto vi sono limiti e differenze qui che fanno eco alla verità che è generics are not templates.
Mi sono permesso di semplificare il tuo esempio. Si prega di annullare se non si è d'accordo. – usr
Per essere onesti, questo sembra un intelligente headf ** k. Cosa c'è di sbagliato nei modi più tradizionali di rappresentare gli alberi usando invece la composizione? Cosa ti compra? Spero che non sembri troppo antagonista. Sono solo curioso. – spender
@spender dimezza il numero di allocazioni e riduce il numero di riferimenti indiretti che è necessario seguire. Quindi nel codice ad alte prestazioni potrebbe essere un compromesso ragionevole. Per gli alberi più piccoli è probabilmente una cattiva idea. – CodesInChaos