阻止Autofac提交IEnumerable <>

时间:2018-12-20 19:55:15

标签: c# autofac ienumerable

我正在寻找一种方法来阻止Autofac自动在构造函数中填充IEnumerable<>

例如,我有一个名为School的类,其中包含以下构造函数

public School(string name) {...}
public School(string name, IEnumerable<IStudent> students) {...}

您可以使用第一个构造函数创建School对象,然后使用AddStudent方法将学生添加到学校。

您可以使用第二个构造函数创建School,并传递要构造School对象时要添加的学生集合。

如果我创建Func<string, ISchool> schoolFactory,然后调用schoolFactory.Invoke("Test"),则Autofac将使用第二个构造函数并自动创建一个新的Student对象。

IStudent接口和Student类已向Autofac注册,并且Student类具有默认构造函数。那里有默认构造函数,因为当用户添加新的Student时,它将在我们的UI中使用。用空白名称创建新的Student,并且在创建Student对象之后,用户可以输入名称。

我尝试了以下方法...

  1. 从Student中删除默认构造函数。这有效,但是这意味着我必须使用其他构造函数并传递string.Empty作为学生姓名。这样做的主要问题是,我们还有其他一些用于创建新对象的通用代码,这些代码要求我们的类具有默认构造函数。这也不是我们所有课程的解决方案。

  2. IEnumerable<IStudent>更改为List<IStudent>。这可以正常工作,这是我在代码中开始做的事情,但是随后强制使用List <>而不是通用的IEnumerable<>。只是不够灵活。

  3. 创建Func<string, IEnumerable<IStudent>, ISchool> schoolFactory并使用schoolFactory.Invoke("Test", Enumerable.Empty<IStudent>)。这也有效。它是更多的代码,但我想它是更明确的。

有没有一种通用方法可以阻止Autofac自动填充IEnumerable?

1 个答案:

答案 0 :(得分:3)

好问题。简短的答案是:我认为这是不可能的。我并不是真的不喜欢软件工程,所以这里有一个更长的解释:

您在这里看到的是Autofac中的所谓“隐式关系类型”。具体来说,the one that supports resolving collections。这些通过registration sources在Autofac中实现。注册源是一种基于给定条件(在这种情况下,该类型的收集方面)动态处理注册的方法。您可以在container.ComponentRegistry.Sources属性的容器中检查这些来源;最后一个应该是对此负责的人。因此,要禁用此功能,您必须能够以某种方式从容器中删除此注册源,但要注意的是:此属性的类型为IEnumerable<IRegistrationSource>,这意味着它是只读的,并不意味着要被干预(即使在运行时是数组)。

但是,如果您对其他解决问题的方法感兴趣,我可以推荐其他方法:

  1. 您说您有一个UI,并且ctor的默认Student在那里,以便用户界面可以处理此类型。听起来您在让用户界面干扰对象模型的设计。我建议您尝试实现一些旨在分离UI和BLL的架构模式,例如MVVM或MVC。例如,在MVVM的情况下,您的UI可能有一个StudentViewModel,该UI可以具有默认的ctor,并且只能使用参数化的ctor来保持Student的干净。
  2. 如果这不是选项(因为您说不是所有类的选项),则可以在注册类型(see the docs)时尝试指定构造函数。在这种情况下,您可以手动注册非集合构造函数,而Autofac使用该构造函数:

    builder.RegisterType<School>().UsingConstructor(typeof(string));
    

编辑

或者,如果您真的很想完全禁用整个功能,那么我想您可以成为核心并对其开放源代码:)创建您自己的fork,找到src / Autofac / ContainerBuilder。 cs文件,然后在void RegisterDefaultAdapters(IComponentRegistry componentRegistry)方法中,可以看到正在添加的默认注册源。只需删除显示componentRegistry.AddRegistrationSource(new CollectionRegistrationSource());的行(文件中develop分支的第247行),然后构建自己的行并使用它。不要忘记修改单元测试;)