#c# #dependency-injection #autofac
#c# #внедрение зависимостей #autofac
Вопрос:
Я использую версию Autofac 6.0.0, и у меня возникают проблемы при попытке зарегистрировать следующий общий абстрактный класс:
public abstract class wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja> : ViewModelBase
where TGrupo : class, IIdEntero, IPadreId, new()
where THoja : class,IIdEntero, IGrupoId, new()
where TNodoGrupo : TreeItemHierarchicalVM, new()
where TNodoHoja : TreeItemLeafVM, new()
{
}
Я пытался зарегистрировать это во многих формах, получая разные ошибки, где наиболее распространенным является «Тип wndArbolVM`4 [TGrupo, TNodoGrupo,THoja, TNodoHoja] является общим определением типа»
Редактировать: вот как я пытаюсь зарегистрировать вещи (я использовал Autofac версии 3.5.0 до обновления до 6.0.0, и это сработало как шарм):
var builder = new ContainerBuilder();
Assembly[] ensamblados =
{
Assembly.GetExecutingAssembly(),
Assembly.GetAssembly(typeof(Configurator)),
Assembly.GetAssembly(typeof(BaseAPI)),
Assembly.GetCallingAssembly()
};
builder.RegisterAssemblyTypes(ensamblados).Where(p => p.BaseType == typeof(BaseAPI)).SingleInstance();
builder.RegisterByAttributes(ensamblados);
builder.RegisterType<wndPrincipal>().SingleInstance();
builder.RegisterType<Sesion>().SingleInstance();
builder.RegisterInstance(LogManager.GetCurrentClassLogger()).As<ILogger>();
builder.RegisterInstance(new Entorno(Entorno.GESTION)).As<Entorno>();
builder.RegisterInstance(this).As<App>();
Container = builder.Build();
Правка2: полная трассировка стека
en System.Dynamic.Utils.TypeUtils.ValidateType(Type type)
en System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments)
en Autofac.Core.Activators.Reflection.ConstructorBinder.GetConstructorInvoker(ConstructorInfo constructorInfo)
en System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
en Autofac.Core.Activators.Reflection.ConstructorBinder..ctor(ConstructorInfo constructorInfo)
en Autofac.Core.Activators.Reflection.ReflectionActivator.ConfigurePipeline(IComponentRegistryServices componentRegistryServices, IResolvePipelineBuilder pipelineBuilder)
en Autofac.Core.Registration.ComponentRegistration.BuildResolvePipeline(IComponentRegistryServices registryServices, IResolvePipelineBuilder pipelineBuilder)
en Autofac.Core.Registration.ComponentRegistration.BuildResolvePipeline(IComponentRegistryServices registryServices)
en Autofac.Core.Registration.ComponentRegistryBuilder.Build()
en Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
en App.Application_Startup(Object sender, StartupEventArgs e) en
en System.Windows.Application.OnStartup(StartupEventArgs e)
en System.Windows.Application.<.ctor>b__1_0(Object unused)
en System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
en System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
Любая помощь будет оценена
Ответ №1:
Здесь недостаточно для фактического устранения проблемы — нет фактической трассировки стека, нет кода, показывающего, как вы пытаетесь зарегистрировать вещи и т. Д.
Однако вы не можете зарегистрировать абстрактный класс, потому что вы не можете создавать экземпляры абстрактного класса. Все, что делает Autofac, — это, по сути, вызов new
для вас. Если вы подумаете об этом, вы не сможете этого сделать:
var x = new wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>();
Вы не можете «создать» абстрактный класс. Это все, что делает DI — он вызывает все нужные вам конструкторы.
Теперь вы можете зарегистрировать конкретный класс как абстрактный класс, и это действительно работает. Допустим, у вас есть это:
public class DerivedViewModel : wndArbolVM<A, B, C, D>
{
// contents here
}
Теперь у вас есть конкретный класс, который вы можете зарегистрировать.
var builder = new ContainerBuilder();
builder.RegisterType<DerivedViewModel>()
.As<wndArbolVM<A, B, C, D>>();
var container = builder.Build();
// This should work:
using var scope = container.BeginLifetimeScope();
var model = scope.Resolve<wndArbolVM<A, B, C, D>>();
// model will be a DerivedViewModel
Но, опять же, поскольку вы не можете создать экземпляр абстрактного класса, это не сработает:
var builder = new ContainerBuilder();
// This will never work. You can't create instances
// of an abstract class. The thing in RegisterType<T>
// is what will (basically) be used in
// new T();
// and you can't do
// new wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>();
// even if you used concrete type parameters like
// new wndArbolVM<A, B, C, D>();
builder.RegisterType<wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>>();
Вопрос был обновлен 4 декабря 2020 года, чтобы добавить дополнительную регистрационную информацию.
Показанная новая информация о регистрации не показывает никакого фактического использования wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>
типа. Фактическое полное исключение с трассировкой стека, чтобы указать, где происходит исключение, все еще не включено в вопрос, поэтому трудно точно определить, где возникает проблема. Это исключение будет ключом к устранению неполадок — не только сообщение, но и трассировка стека.
Что касается обновлений вопроса:
RegisterAssemblyTypes
Вызов регистрирует только те объекты, в которых указан базовый типBaseAPI
, ноwndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>
является aViewModelBase
, и я должен предположить, что это не так.RegisterByAttributes
Метод не поставляется с Autofac, поэтому я не знаю, что он делает; и я не вижу никаких атрибутов поwndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>
классу, поэтому я не могу догадаться.
Тем не менее, я отмечаю, что вы использовали Autofac 3.5.0 и сразу перешли к Autofac 6. Многое изменилось с июня 2014 года, когда был выпущен Autofac 3.5.0. Каждая основная версия (4.x, 5.x, 6.x) указывает на кардинальные изменения, а не только на новые функции. Мы сделали все возможное, чтобы вещи были совместимы, но это не гарантировано на 100%, и вам нужно будет учитывать это в своем коде.
Если бы я столкнулся с этим, я бы замедлился и попытался повторить это в модульном тестировании. Например, может быть, есть модульный тест, который регистрирует только один экземпляр wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>
и разрешает его. Не все остальные вещи, сканирование сборки и все такое, а просто … одна вещь. Или, только это одно и очень минимальное количество других вещей, вероятно, достаточно объектов-заглушек, чтобы все заработало. Как только у меня это заработает… теперь сравните. В чем разница между моим тестовым кодом, который работает, и моей более сложной реальной системой?
Оттуда он просматривает код и находит проблему. Возможно, используйте модульный тест как место, где можно попробовать что-то изолированно. Вместо регистрации заглушки, возможно, переключитесь — один за другим — чтобы начать регистрировать «реальные вещи». Выясните, когда он ломается. Это укажет вам место для поиска в реальной, более сложной системе.
К сожалению, это все, что я могу здесь предложить. Похоже, у вас довольно сложная настройка системы, и из-за недостатка информации и обновления трех основных версий Autofac многое из того, что должно произойти, зависит от конкретного приложения. Как бы мне ни хотелось помогать, на самом деле у меня не так много дополнительного времени для повторения циклов обновления вопросов / ответов. Надеюсь, то, что здесь, может разблокировать вас и помочь вам разобраться в проблеме.
Комментарии:
1. Редактировать, добавлен регистрационный код и комментарий, чтобы упростить задачу.
2. Обновления на самом деле не имеют смысла или не помогают.
RegisterByAttributes
это не метод Autofac, это что-то в вашем коде.wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>
этоViewModelBase
не aBaseAPI
, поэтому регистрация не скрыта при сканировании сборки. Я добавлю к своему ответу рекомендацию по устранению неполадок, но я не смогу вернуться сюда и продолжать «перебирать» решение.3. RegisterByAttributes — это из github.com/droyad/Autofac . Регистрация атрибутов. В любом случае, спасибо за ваше время и помощь. Я постараюсь последовать вашему совету и вернусь с решением для этого.