繁体   English   中英

Autofac:注册通用抽象 class

[英]Autofac: register generic abstract class

我正在使用 Autofac 6.0.0 版本,但在尝试注册以下通用抽象 class 时遇到了麻烦:

 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()
{
}

我曾尝试在许多 forms 中注册此错误,其中最常见的是“类型 wndArbolVM`4[TGrupo,TNodoGrupo,THoja,TNodoHoja] 是通用类型定义”

编辑:这是我尝试注册的方式(我在更新到 6.0.0 之前使用的是 Autofac 3.5.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();

Edit2:完整的堆栈跟踪

  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)

任何帮助,将不胜感激

这里不足以实际解决问题 - 没有实际的堆栈跟踪,没有显示您如何尝试注册事物的代码等。

但是,您无法注册抽象 class ,因为您无法创建抽象 class 的实例。 Autofac 所做的一切——基本上——为你调用new 如果你考虑一下,你不能这样做:

var x = new wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>();

你不能“新建”一个抽象的 class。 这就是 DI 所做的一切——它会为您调用所有正确的构造函数。

现在,您可以将具体的 class 注册抽象 class,这确实有效。 假设你有这个:

public class DerivedViewModel : wndArbolVM<A, B, C, D>
{
  // contents here
}

现在您有了一个可以注册的具体 class。

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

但是,同样,由于您无法创建抽象 class 的实例,这将不起作用:

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>>();

问题已于 2020 年 12 月 4 日更新,以添加更多注册信息。

显示的新注册信息未显示wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>类型的任何实际使用情况。 带有堆栈跟踪的实际完整异常,以指示异常发生的位置仍未包含在问题中,因此很难确定问题发生的位置。 该异常将是解决此问题的关键——不仅是消息,还有堆栈跟踪。

至于问题的更新:

  • RegisterAssemblyTypes调用仅注册基本类型为BaseAPIwndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>ViewModelBase的东西,我必须假设它不在其中。
  • RegisterByAttributes方法不是 Autofac 附带的,所以我不知道它的作用; 而且我没有看到wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja> class 的任何属性,所以我无法猜测。

但是,我确实注意到您使用的是 Autofac 3.5.0 并直接使用 Autofac 6。自 2014 年 6 月发布 Autofac 3.5.0 以来,发生了很多变化。 每个主要版本(4.x、5.x、6.x)都表示重大更改,而不仅仅是新功能。 我们已尽最大努力保持兼容性,但不能保证 100%,您需要在代码中考虑到这一点。

如果是我遇到这种情况,我会放慢速度并尝试在单元测试中重现它。 例如,也许有一个单元测试注册一个wndArbolVM<TGrupo, TNodoGrupo, THoja, TNodoHoja>实例并解析它。 不是所有其他的东西,装配扫描和一切,但只是......一件事。 或者,只有那一件事和非常少量的其他东西,可能只是足够的存根对象来使事情正常工作。 一旦我让它工作......现在比较。 我的有效测试代码和我更复杂的真实系统有什么不同?

从那里开始遍历代码并定位问题。 也许使用单元测试作为一个单独尝试的地方。 与其注册存根,不如逐一切换以开始注册“真实事物”。 弄清楚它什么时候破裂。 这将为您指明一个可以查看真实、更复杂系统的地方。

不幸的是,这就是我在这里所能提供的。 看起来您设置了一个非常复杂的系统,并且在缺乏信息和跨三个主要版本的 Autofac 升级之间,需要发生的很多事情都是特定于应用程序的。 尽管我愿意提供帮助,但我真的没有太多额外的时间来迭代问题更新/答案更新周期。 希望这里的内容可以解除您的障碍,让您走上解决问题的道路。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM