Autofac: зарегистрировать общий абстрактный класс

#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> является a ViewModelBase , и я должен предположить, что это не так.
  • 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 не a BaseAPI , поэтому регистрация не скрыта при сканировании сборки. Я добавлю к своему ответу рекомендацию по устранению неполадок, но я не смогу вернуться сюда и продолжать «перебирать» решение.

3. RegisterByAttributes — это из github.com/droyad/Autofac . Регистрация атрибутов. В любом случае, спасибо за ваше время и помощь. Я постараюсь последовать вашему совету и вернусь с решением для этого.