КРАТКАЯ ФОРМА (!)
В ответ на комментарий Джона Скита я хочу, чтобы C # сделал так, чтобы обобщенный во время компиляции расширялся и наследовал один из его универсальных параметров (как демонстрирует Кирк Волл):
public class Generic<TBase> : TBase {
}
Этот класс, конечно, не сможет переопределить какие-либо члены TBase (если, возможно, если не будет применено ограничение) и должен будет повторить все открытые + защищенные конструкторы TBase без изменений - автоматически переадресовывать вызовы на базу.
Длинная форма вопроса показывает абстрактный + конкретный класс, который представляет общий шаблон для реализации данного интерфейса - но который, поскольку C # не допускает множественное наследование, не может быть легко применен поверх другого базового класса без клонирования весь код и прикрепление базового класса под абстракцией - не совсем СУХОЙ!
ДОЛГО ФОРМА
Я знаю технические причины, по которым следующий код не работает - генерики скомпилированы во время выполнения, а не шаблоны времени компиляции - но мне любопытно узнать, почему дизайнеры C # выглядят настолько сдержанными, чтобы идти по этому пути с язык (я видел цитируемость цитируется, но трудно понять это). Я также хотел бы знать, как вы, ребята, реализовали бы этот шаблон.
У меня есть интерфейс для объекта, который разрешает зависимости через IDependencyResolver:
public interface IDependant
{
IDependencyResolver Resolver { get; set; }
}
У меня тогда есть абстрактный класс
public abstract class DependantBase : IDependant
{
#region IDependant Members
public abstract IDependencyResolver Resolver
{
get; set;
}
#endregion
public virtual TDependency ResolveDependency<TDependency>(
string name, params object[] args)
{
//null checks elided
return Resolver.Resolve<TDependency>(name, args);
}
public TDependency ResolveDependency<TDependency>(
params object[] args)
{
return ResolveDependency<TDependency>(null, args);
}
}
И, наконец, класс экземпляра, который просто материализует свойство Resolver:
public class Dependant : DependantBase
{
public override IDependencyResolver Resolver
{ get; set; }
}
Таким образом, я могу получить этот тип и переопределить как свойство Resolver, так и способ выполнения операции разрешения.
Я использовал его на ванильном типе (то есть на другом, у которого нет базы), а затем я пришел написать MVC-контроллер.
То, что я хочу, чтобы мог сделать, это повторить два вышеупомянутых класса, но реализовать их следующим образом:
//'injects' the DependantBase functionality
//between TBase and the deriving class
public abstract class DependantBase<TBase> : TBase, IDependant
{
//as DependantBase above
}
//and then have Dependant<TBase>:
public class Dependant : DependantBase<TBase>
{
//as Dependant above
}
Таким образом, если бы вышеупомянутое было возможно, я мог бы просто сделать это:
public class HomeController : Dependant<System.Web.Mvc.Controller>
{
}
А теперь HomeController наследуется от Dependant<System.Web.Mvc.Controller>
, который, в свою очередь, наследуется от System.Web.Mvc.Controller
.
Ключевым моментом здесь является то, что я хочу сохранить предыдущий шаблон возможности переопределения как свойства, так и вспомогательного метода ResolveDependency - но я не хочу продолжать клонировать один и тот же код инфраструктуры для каждой новой ветви типов (т. е. когда какой-то фреймворк требует нового существующего базового типа).
Это явно не универсальный термин .Net, потому что я не уверен, как вы вообще начали бы представлять это в метаданных - но компилятор C # , безусловно, может воспринимать это как шаблон вместо этого и разверните его во время компиляции (боже, этого достаточно уже с деревьями выражений, интерфейсом DLR, встроенными делегатами, блоками итераторов и автоматически получить / установить свойства!).
Единственный способ увидеть что-то подобное - это вставить его в плагин Visual Studio (расширение нового языка или что-то в этом роде) или даже в текстовый шаблон.