4

我有以下测试

[TestFixture]
public class Test
{
    public interface IMy { }

    class MyClass : IMy { }

    class MyClass2 : IMy { }

    [Test]
    public static void Go()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyClass>().AsImplementedInterfaces();
        builder.RegisterType<MyClass2>().AsImplementedInterfaces();
        var container = builder.Build();
        var resolved = container.Resolve<IMy>();
        Console.WriteLine(resolved);
    }
}

为什么当实现明显冲突时它不会抛出异常?如果发现这样的冲突,如何让它抛出异常?

UPDATE 带有注册检查的解决方案几乎可以,但是失败时有简单的情况:

[TestFixture]
public class Test
{
    public interface IPlugin
    {
    }

    public interface IMy
    {

    }

    class MyClass : IMy, IPlugin
    {
        public void Dispose()
        {
        }
    }

    class MyClass2 : IPlugin
    {
        public void Dispose()
        {
        }
    }

    public class SingleRegistrationModule : Module
    {
        protected override void AttachToComponentRegistration(
            IComponentRegistry componentRegistry, 
            IComponentRegistration registration)
        {
            foreach (var service in registration.Services)
            {
                var registrations = componentRegistry.RegistrationsFor(service);
                if (registrations.Count() > 1)
                {
                    throw new Exception(
                        "Can't register '{registration.Activator.LimitType}' as '{service}'" + 
                        " because '{registrations.First().Activator.LimitType}' is already registered");
                }
            }
        }
    }

    [Test]
    public static void Go()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyClass>().AsImplementedInterfaces();
        builder.RegisterType<MyClass2>().AsImplementedInterfaces();
        builder.RegisterModule<SingleRegistrationModule>();
        var container = builder.Build();
        var resolved = container.Resolve<IMy>();
        Console.WriteLine(resolved);
    }
}

在这种情况下,没有人解析 IInitializable,因此可以接受多个实现。此外,在某些情况下,多个实现是可以的,例如 IPluginToSomething

4

2 回答 2

7

Autofac 不抛出异常的原因是 Autofac 将同一接口的多个注册视为集合的一部分。例子:

builder.RegisterType<MyClass>().As<IMy>();
builder.RegisterType<MyClass2>().As<IMy>();
var container = builder.Build();
var collection = container.Resolve<IEnumerable<IMy>>();
Console.WriteLine(collection.Count()); // prints "2"

如果进行了多次注册,调用Resolve<IMy>()将只解决其中一个(第一个或最后一个,但我总是忘记它是哪一个)。我个人认为这是 Autofac(和其他 DI 容器)中的设计缺陷,因为这会导致您的应用程序静默失败,而不是快速失败。在Simple Injector中,选择严格分离集合的注册(如此所述)以防止这些类型的配置错误。

于 2016-05-10T09:12:08.087 回答
1

正如Steven所说,Autofac将考虑将同一服务的多次注册视为集合的一部分。

如果您不想要这种行为,您可以使用Autofac模块添加检查:

public class SingleRegistrationModule : Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistry componentRegistry, 
        IComponentRegistration registration)
    {
        foreach (var service in registration.Services)
        {
            var registrations = componentRegistry.RegistrationsFor(service);
            if (registrations.Count() > 1)
            {
                throw new Exception(
                    $"Can't register '{registration.Activator.LimitType}' as '{service}'" + 
                    $" because '{registrations.First().Activator.LimitType}' is already registered");
            }
        }
    }
}

然后您可以使用以下方法注册模块:

builder.RegisterModule<SingleRegistrationModule>();

构建容器时会抛出异常。

于 2016-05-10T10:09:03.977 回答