为什么解析一个集合也会创建 1 个元素?

Why resolving a collection also create 1 element?

我在 Mono 上使用 Autofac 3.5.2,当我尝试注册一个通用集合然后解析它时,我得到了正确的实例,其中已经添加了 1 个正确类型的元素。用代码来解释:

class Fake {}

var builder = new ContainerBuilder();
builder.RegisterType<Fake>();
bilder.RegisterGeneric(typeof(List<>));

var scope = builder.Build();

var list = scope.Resolve<List<Fake>>();

Console.WriteLine(list.Count); // => prints 1!

这是意料之中的事吗?为什么?我怎样才能避免这种情况?

Autofacbuilt-in support for collection 并且默认情况下会在解析服务时尝试使用具有最多可用参数的构造函数。

Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container
> http://autofac.readthedocs.org/en/latest/register/registration.html#register-by-type

List<T> 包含一个采用 IEnumerable<T> 的构造函数。 当 Autofac resolve List<Fake> 时,它将选择带有 IEnumerable<T> 的构造函数,然后 resolve IEnumerable<T> 将解析所有可用的 instanceT

如果您注册了多个 FakeAutofac 将在您解析时解析所有这些。例如:

var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>)); 

var scope = builder.Build();

var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 2!

注册时可以指定使用哪个构造函数List<T>

var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>)).UsingConstructor(Type.EmptyTypes);

var scope = builder.Build();

var list = scope.Resolve<List<IFake>>();

Console.WriteLine(list.Count); // => prints 0!

或者您可以使用 Build 方法中的 ContainerBuildOptions.ExcludeDefaultModules 参数忽略默认行为

var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterGeneric(typeof(List<>)); 

var scope = builder.Build(ContainerBuildOptions.ExcludeDefaultModules);

var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 0!

我不建议删除默认行为,除非你真的知道你在做什么。