Рассмотрим, что произойдет, если мы отклоняемся от CRTP конвенции, написав ...
public class Foo : TreeNode<Foo>
{
}
public class Bar : TreeNode<Foo> // parting from convention
{
}
... и затем вызвать приведенный выше код следующим образом:
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
либо тип T
, как и в случае Foo
класса или подкласса TreeNode<T>
в Bar
класса случае, так как Bar
наследуется от TreeNode<Foo>
- так или иначе позволяет опускать клали SetParent
и это упущение избежать недопустимое исключение броска с момента назначение во всех случаях является законным. Затраты на это больше не могут свободно использовать T
во всех местах, как ранее использовалось, что приносит большую часть ценности CRTP.
Мой коллега считает себя новичком в языке/языке, пока он не может честно сказать, что он «использовал его в гневе»; то есть он знает язык достаточно хорошо, чтобы быть расстроенным, что нет ни одного способа выполнить то, что ему нужно, или что это так больно. Это очень хорошо может быть одним из таких случаев, поскольку здесь существуют ограничения и различия, которые отражают правду, что generics are not templates.
Я позволил себе упростить ваш пример. Пожалуйста, верните, если вы не согласны. – usr
Если честно, это выглядит как умный голова ** k. Что не так с более традиционными способами представления деревьев с использованием композиции? Что это вы покупаете? Надеюсь, это звучит не слишком антагонистично. Мне просто интересно. – spender
@spender его половину количества распределений, и уменьшает количество косвенных действий, которые вам нужно следовать. Поэтому в коде высокой производительности это может быть разумным компромиссом. Для небольших деревьев это, вероятно, плохая идея. – CodesInChaos