Каждый раз, когда я делаю простой интерфейс более сложным, добавляя к нему привязку к параметру self-referencing («reflexive»). Например, я мог бы превратить это:Ограничения параметра рефлексивного типа: X <T> где T: X <T> - любые более простые альтернативы?
interface ICloneable
{
ICloneable Clone();
}
class Sheep : ICloneable
{
ICloneable Clone() { … }
} //^^^^^^^^^^
Sheep dolly = new Sheep().Clone() as Sheep;
//^^^^^^^^
в:
interface ICloneable<TImpl> where TImpl : ICloneable<TImpl>
{
TImpl Clone();
}
class Sheep : ICloneable<Sheep>
{
Sheep Clone() { … }
} //^^^^^
Sheep dolly = new Sheep().Clone();
Основное преимущество: реализующий тип (например, Sheep
) теперь может ссылаться на себя вместо своего базового типа, уменьшая потребность в (как показано в последней строке кода).
Хотя это очень приятно, я также заметил, что эти ограничения параметров типа не являются интуитивными и имеют тенденцию становиться действительно трудными для понимания в более сложных сценариях. *)
Вопрос: Кто-нибудь знает другой C# код шаблона, который достигает того же эффекта или что-то подобное, но в более легком для хватки моды?
*) Этот шаблон кода может быть неинтуитивными и трудно понять, например, в этих отношениях: «Если
T
являетсяX<T>
, тоX<T>
действительно являетсяX<X<…<T>…>>
»
Объявление
X<T> where T : X<T>
появляется рекурсивным, и можно было бы задаться вопросом, почему компилятор doesn't get stuck in an infinite loop, рассуждения, (Но ограничения явно не разрешаются, как это.)Для реализаторов, это может быть не очевидно, какой тип должен быть указан вместо
TImpl
. (Ограничение будет в конечном итоге позаботиться об этом.)После того, как вы добавите больше параметров типа и подтипы отношений между различными родовыми интерфейсами к смеси, вещи становятся неуправляемыми довольно быстро.
Вы будете рады узнать, что это достаточно распространено, чтобы иметь имя: оно называется «Любопытно повторяющийся шаблон шаблона» (CRTP для краткости). – Cameron
... и это не имеет ничего общего с ограничениями (в качестве стандартных шаблонов на C++ их вообще нет). – Krizz
Есть ли причина, по которой это не просто «интерфейс ICloneable {T Clone(); } '? –