Каждый раз я делаю простой интерфейс более сложным, добавляя к нему ограничение параметра саморегуляции ( "рефлексивный" ). Например, я могу включить это:
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
) теперь может ссылаться на себя, а не на его базовый тип, что уменьшает необходимость в литье типов (как показано в последней строке кода).
Хотя это очень хорошо, я также заметил, что эти ограничения параметров типов не являются интуитивными и имеют тенденцию становиться действительно трудными для понимания в более сложных сценариях. *)
Вопрос: Кто-нибудь знает о другом шаблоне кода С#, который достигает того же эффекта или чего-то подобного, но более легкого для восприятия способа?
*) Этот шаблон кода может быть неинтуитивным и трудно понять, например. следующим образом:
Объявление
X<T> where T : X<T>
представляется рекурсивным, и можно задаться вопросом, почему компилятор не застревает в бесконечном цикле, рассуждение: "ЕслиT
являетсяX<T>
, тоX<T>
действительно являетсяX<X<…<T>…>>
." (Но ограничения, очевидно, не решены так.)Для разработчиков это может быть не очевидно, какой тип следует указывать вместо
TImpl
. (Ограничение в конечном итоге позаботится об этом.)После добавления дополнительных параметров типа и отношений подтипов между различными универсальными интерфейсами в микс, ситуация становится неуправляемой довольно быстро.