Search code examples
autofac

Why does IContainer.IsRegistered(Type serviceType) add registrations?


Why does IContainer.IsRegistered(Type serviceType) add registrations?

Type serviceType = typeof (string[]);
int rc = container.ComponentRegistry.Registrations.Count();
container.IsRegistered(serviceType);
int rc2 = container.ComponentRegistry.Registrations.Count();
Assert.AreEqual(rc, rc2);

The mentioned behavior could make the following side effect:

public class Test
{
      public Entity[] Entities { get; set; }
}
//...
var bldr = new ContainerBuilder();
bldr.RegisterModule<ArraysInjectionGuardModule>();
var container = bldr.Build();
var t = new Test();
container.InjectProperties(t);
Assert.IsNull(t.Entities);

Because container.InjectProperties(...); invokes container.IsRegistered(..) and passes typeof(Entity[]) as an argument, t.Entities is initialized with an empty array. I was a bit confused when I discovered this behavior.


Solution

  • I found that the mentioned behavior is by design

    Here is a workaround to avoid injection of empty arrays.
    It uses reflection so use this approach on your own risk.
    Please be aware that it decreases resolution performance. You just need to register the following module:

    containerBuilder.RegisterModule<ArraysInjectionGuardModule>();
    
    class ArraysInjectionGuardModule : Module
    {
        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
            IComponentRegistration registration)
        {
            registration.Activating += (s, e) =>
            {
                var ts = e.Component.Services.Single() as TypedService;
                if (ts != null && ts.ServiceType.IsArray &&
                    !e.Context.IsRegistered(ts.ServiceType.GetElementType()))
                {
                    FieldInfo t = e.GetType().GetField("_instance",
                                                       BindingFlags.Instance | BindingFlags.NonPublic);
                    t.SetValue(e, null);
                }
            };
        }
    }