По моему мнению, у вас есть три более или менее реальных варианта.
1) Сделайте контроллер универсальным, а затем передайте параметр типа контроллера самому введенному типу (см. Ниже).Таким образом, контроллер будет знать о конкретном типе T
и сможет использовать его без каких-либо странных танцев.Однако следующий вопрос - как объяснить все эти вещи в рамках, которые будут разрешать такой контроллер?DotNet Core по умолчанию не поддерживает универсальные контроллеры.К счастью, такой трюк вполне можно сделать.Вы можете прочитать некоторые подробности об этом в этом ответе и далее по ссылке к документации Microsoft .Это не просто, так что это может быть излишним для вашей задачи ... Я просто не уверен, что ваша задача на самом деле.
[Route("api/[controller]")]
public class ValuesController<T> : Controller where T: class, new()
{
private readonly AbstractLogic<T> _logic;
public ValuesController(AbstractLogic<T> logic)
{
_logic = logic;
}
2) Используйте отражение, чтобы разрешить AbstractLogic<T>
.Прежде всего, вам нужно объявить приватное поле для хранения ссылки на AbstractLogic<T>
.Единственный способ, как это можно сделать, описан здесь .После этого вам нужно разрешить его, используя определенный тип , и единственный способ сделать это - создать этот тип во время выполнения с помощью отражения.Такие вещи имеют тенденцию становиться довольно громоздкими довольно быстро.
3) Самый разумный вариант, на мой взгляд.Вам необходимо ввести базовый неуниверсальный тип для AbstractLogic
, наследовать от него AbstractLogic<T>
, зарегистрировать конкретную универсальную реализацию в контейнере как неуниверсальную AbstractLogic
, а затем просто внедрить неуниверсальный AbstractLogic
в свой контроллер.Таким образом, вам нужно переместить универсальную логику в общие классы, в то же время перенеся интерфейс существенного компонента в неуниверсальный родительский AbstractLogic
.Однако это добавляет ограничение: основной компонент неуниверсального интерфейса никоим образом не должен зависеть от конкретного параметра универсального типа дочернего класса.Поскольку я понятия не имею об остальной части вашего кода, я не могу сказать, возможно ли это в вашем случае или нет.Общая идея кода приведена ниже.
// class hierarchy
public abstract class AbstractLogic
{
public string DoStufF()
{
return DoStufFInternal();
}
protected abstract string DoStufFInternal();
}
// Here 'where' constraint is not essential, I'm just lazy enough
// and implemented property setting in the dumbest possible way which required the constraint :)
public abstract class AbstractLogic<T> : AbstractLogic where T: class, new()
{
protected AbstractLogic()
{
SomeProperty = new T();
}
public T SomeProperty { get; private set; }
}
public class DefaultLogic : AbstractLogic<ClassA>
{
protected override string DoStufFInternal()
{
return $"Default stuff: SomeProperty = {SomeProperty.ToString()}";
}
}
public class SpecificLogic : AbstractLogic<ClassB>
{
protected override string DoStufFInternal()
{
return $"Specific stuff: SomeProperty = {SomeProperty.ToString()}";
}
}
public class ClassA
{
public override string ToString()
{
return "Class A representation";
}
}
public class ClassB
{
public override string ToString()
{
return "Class B representation";
}
}
// registering class
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.Name.StartsWith(Settings.GetCurrentMode().ToString()))
.As<AbstractLogic>()
.InstancePerLifetimeScope();
// and using it in the controller
[Route("api/[controller]")]
public class DITestController : Controller
{
private readonly AbstractLogic _logic;
public DITestController(AbstractLogic logic)
{
_logic = logic;
}
[HttpGet]
public IActionResult Get()
{
return Ok(_logic.DoStufF());
}
}