C# Autofac忽略注册冲突

C# Autofac忽略注册冲突,c#,.net,autofac,autofac-configuration,C#,.net,Autofac,Autofac Configuration,我有以下测试 [TestFixture] public class Test { public interface IMy { } class MyClass : IMy { } class MyClass2 : IMy { } [Test] public static void Go() { var builder = new ContainerBuilder(); builder.RegisterType&

我有以下测试

[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);
    }
}
[TestFixture]
公开课考试
{
公共接口IMy{}
类MyClass:IMy{}
类MyClass2:IMy{}
[测试]
公共静态void Go()
{
var builder=new ContainerBuilder();
builder.RegisterType().AsImplementedInterfaces();
builder.RegisterType().AsImplementedInterfaces();
var container=builder.Build();
var resolved=container.Resolve();
控制台写入线(已解决);
}
}
为什么它在实现明显冲突时不抛出异常?如果发现这样的冲突,如何使其抛出异常

更新 注册检查的解决方案几乎可以,但是 当它失败时,有一种简单的情况:

[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);
    }
}
[TestFixture]
公开课考试
{
公共接口IPlugin
{
}
公共接口IMy
{
}
类别MyClass:IMy,IPlugin
{
公共空间处置()
{
}
}
类别MyClass2:IPlugin
{
公共空间处置()
{
}
}
公共类SingleRegistrationModule:模块
{
受保护的覆盖无效AttachToComponentRegistration(
IComponentRegistry组件注册表,
iComponent(组件注册)
{
foreach(registration.Services中的var服务)
{
var registrations=componentRegistry.RegistrationsFor(服务);
如果(registrations.Count()>1)
{
抛出新异常(
“无法将{registration.Activator.LimitType}注册为{service}'”
“因为“{registrations.First().Activator.LimitType}”已注册”);
}
}
}
}
[测试]
公共静态void Go()
{
var builder=new ContainerBuilder();
builder.RegisterType().AsImplementedInterfaces();
builder.RegisterType().AsImplementedInterfaces();
builder.RegisterModule();
var container=builder.Build();
var resolved=container.Resolve();
控制台写入线(已解决);
}
}

在这种情况下,没有人解析IIInitializable,因此可以接受多个实现。此外,当mulltiple实现正常时,也会出现一些情况,例如IPluginToSomething

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"
builder.RegisterType().As();
builder.RegisterType().As();
var container=builder.Build();
var collection=container.Resolve();
Console.WriteLine(collection.Count());//打印“2”
如果进行了多个注册,调用
Resolve()
将只解析其中一个(第一个或最后一个,但我总是忘记它是哪一个)。我个人认为这是Autofac(以及其他DI容器)中的一个设计缺陷,因为这会导致应用程序默默地失败,而不是快速失败。在选择严格地分离集合的注册(如所解释的),以防止这些类型的配置错误时,

如所述,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>();
builder.RegisterModule();

容器构建时将引发异常。

我完全同意你的看法,我也尝试解决了收集问题,但如何覆盖这个有缺陷的默认行为?@Alexilyn:我认为你不能轻易覆盖它,但也许Autofac专家可以回答。我检查了旋转顺序,Autofac将在注入时使用最后一个。感谢您的回答,但似乎有问题。此解决方案引发太多异常。。。假设使用.RegisterType().AsImplementedInterfaces()注册类型;其中一些支持IDisposable、IEnumerable或任何其他没人会解决的接口。此解决方案会报告这些接口的错误。当然,我可以支持异常接口列表,但它不是一个可扩展的解决方案。我甚至尝试过监听诸如ResolveOperationStart和InstanceLookupBeginning之类的事件,但是这些事件似乎没有暴露请求的接口。这太奇怪了,没有简单的解决方案。从我的观点来看,100%的Autofac用户应该面对这个问题。我不应该使用ImplementedInterface。