首页 > 解决方案 > Autofac中注册和解析不同TypeOf的不同参数构造函数

问题描述

我有一个有 2 个构造函数的类,在构造函数中有 2 个不同类型的参数,这很好用,直到我有一个构造函数,但是一旦我创建另一个构造函数并尝试解决它,autofac 崩溃并说使用构造函数配置指定构造函数,我尝试在 DI 中注册构造函数,但第一个注册覆盖了第二个

builder.RegisterType<DeviceMasterPageViewModel>().UsingConstructor(typeof(DeviceListModel));
builder.RegisterType<DeviceMasterPageViewModel>().UsingConstructor(typeof(int));

这是我有 2 个构造函数的课程

public DeviceMasterPageViewModel(DeviceListModel scannendDevice)
    {}
 public DeviceMasterPageViewModel(int selectedDeviceID)
    {}

我无法理解我应该如何在 DI 中注册这个类,以便当我传递特定类型的参数时,应该调用指定的 typeof 构造函数

标签: c#.netdependency-injectionautofac

解决方案


您只能通过一种方式向 Autofac 注册组件。最后注册获胜。这就是为什么当您尝试注册两次时它不起作用的原因。

通常,您尝试做的事情与 DI 并不真正兼容。DI 真的希望在您的对象上有一个构造函数,仅此而已。此外,您建议的其中一个构造函数中有一个原始类型 ( int),这对于 DI 也不是很好。

如果 DI 允许两个构造函数......它如何选择?假设在解析上下文中参数int参数DeviceListModel都可用。哪个构造函数是正确的?

如果您int在构造函数中使用......因为您实际上只能注册一个给定的注册System.Type,这意味着您拥有的任何对象都int将获得相同的int值。那正确吗?

所以,说了这么多,假设你仍然真的希望这发生。您将不得不编写自己的一些逻辑。

该逻辑的一部分需要知道您期望构造函数参数来自哪里。它们是您正在解决的应该已经在容器中注册的东西吗?或者它们是你要传递的东西?

也就是说,您有两个基本场景:

# All the stuff the DMPVM needs is _registered_
var b = new ContainerBuilder();
b.Register(3).As<int>();
b.RegisterType<DeviceListModel>().AsSelf();
b.RegisterType<DeviceMasterPageViewModel>().AsSelf();
var c = b.Build();
var d = c.Resolve<DeviceMasterPageViewModel>();

或者

# You plan on _passing in_ the values
var b = new ContainerBuilder();
b.RegisterType<DeviceMasterPageViewModel>().AsSelf();
var c = b.Build();
var d = c.Resolve<DeviceMasterPageViewModel>(new TypedParameter(typeof(int), 3));

(这是评论中提出的问题的症结所在。了解这一点对于您将编写的自定义逻辑类型很重要。)

如果您假设所有内容都将被注册,那么您可能需要编写自己的IConstructorSelector. Autofac 附带了两种,一种与最可用的参数匹配,另一种与特定的构造函数签名匹配。然后,您可以在注册期间提供您的构造函数选择器。

如何准确地写这将取决于你。我认为这不是一个好主意,它会有很多警告,比如如果你有很长的生命周期来解决组件会发生什么;以及它对应用性能有何影响;等等。这完全取决于你。

如果你传递参数,它会更容易一些。您可以注册一个 lambda,而不是编写构造函数选择器。查找参数并根据需要使用它们。这是记录在案的。

它可能是这样的:

b.Register((ctx, plist) => {
  var intParam = plist
    .OfType<TypedParameter>()
    .Where(p => p.Type == typeof(int))
    .FirstOrDefault();
  if(intParam != null) {
    return new DeviceMasterPageViewModel((int)intParam.Value);
  }

  // int param isn't found, do a similar search for the
  // DeviceListModel parameter.
}).As<DeviceMasterPageViewModel>();

如您所见,您可以根据传入的参数在此处执行一些动态工厂样式逻辑。

但是,同样,如果你完全避免这种情况,你的生活会容易得多。


推荐阅读