我正在寻找一种方法来阻止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对象之后,用户可以输入名称。
我尝试了以下方法...
从Student中删除默认构造函数。这有效,但是这意味着我必须使用其他构造函数并传递string.Empty作为学生姓名。这样做的主要问题是,我们还有其他一些用于创建新对象的通用代码,这些代码要求我们的类具有默认构造函数。这也不是我们所有课程的解决方案。
将IEnumerable<IStudent>
更改为List<IStudent>
。这可以正常工作,这是我在代码中开始做的事情,但是随后强制使用List <>而不是通用的IEnumerable<>
。只是不够灵活。
创建Func<string, IEnumerable<IStudent>, ISchool> schoolFactory
并使用schoolFactory.Invoke("Test", Enumerable.Empty<IStudent>)
。这也有效。它是更多的代码,但我想它是更明确的。
有没有一种通用方法可以阻止Autofac自动填充IEnumerable?
答案 0 :(得分:3)
好问题。简短的答案是:我认为这是不可能的。我并不是真的不喜欢软件工程,所以这里有一个更长的解释:
您在这里看到的是Autofac中的所谓“隐式关系类型”。具体来说,the one that supports resolving collections。这些通过registration sources在Autofac中实现。注册源是一种基于给定条件(在这种情况下,该类型的收集方面)动态处理注册的方法。您可以在container.ComponentRegistry.Sources
属性的容器中检查这些来源;最后一个应该是对此负责的人。因此,要禁用此功能,您必须能够以某种方式从容器中删除此注册源,但要注意的是:此属性的类型为IEnumerable<IRegistrationSource>
,这意味着它是只读的,并不意味着要被干预(即使在运行时是数组)。
但是,如果您对其他解决问题的方法感兴趣,我可以推荐其他方法:
ctor
的默认Student
在那里,以便用户界面可以处理此类型。听起来您在让用户界面干扰对象模型的设计。我建议您尝试实现一些旨在分离UI和BLL的架构模式,例如MVVM或MVC。例如,在MVVM的情况下,您的UI可能有一个StudentViewModel
,该UI可以具有默认的ctor
,并且只能使用参数化的ctor
来保持Student的干净。如果这不是选项(因为您说不是所有类的选项),则可以在注册类型(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行),然后构建自己的行并使用它。不要忘记修改单元测试;)