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);
    }
}

実装が明らかに競合しているときに例外をスローしないのはなぜですか? そして、そのような競合が見つかった場合に例外をスローする方法は?

更新 登録チェックを使用したソリューションはほとんど問題ありませんが、失敗する単純な状況があります。

[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>()そのうちの 1 つだけが解決されます (最初または最後ですが、どれがどれであるかは常に忘れてしまいます)。個人的には、これは 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 に答える