Я понимаю, что это старый пост, но мне пришлось решить именно эту проблему.
Вот как вы можете это сделать:
class BaseClass { }
interface OnlyBaseClass<TSelf> where TSelf : BaseClass, OnlyBaseClass<TSelf>
{
}
class ChildClass : BaseClass, OnlyBaseClass<ChildClass> { }
class ImpostorClass : OnlyBaseClass<ImposterClass> { }
interface ImposterInterface : OnlyBaseClass<ImposterInterface > { }
Попробуйте скомпилировать выше. Вы заметите, что он не компилируется (из-за двух самозванцев, одного класса, одного интерфейса).
Ограничение на TSelf можно понимать как:
TSelf должен: наследовать от BaseClass и реализовать OnlyBaseClass <<em> TSelf >
... что может сделать только тип, унаследованный от BaseClass и реализующий OnlyBaseClass .
Вы можете быть умным и делать следующее:
class AdvancedImpostorClass : OnlyBaseClass<ChildClass> {}
... который будет компилироваться. Вы можете предотвратить попадание этих типов самозванцев в ваш код, используя те же ограничения в любых методах, которые принимают их в качестве аргументов, например, так:
public SomeMethod<TBaseAndInterface>(TBaseAndInterface value)
where TBaseAndInterface: BaseClass, OnlyBaseClass<TBaseAndInterface>
{ }
Все это стало возможным благодаря силе F-связанного полиморфизма .