Unity RegisterType with unusual LifetimeManager behavior

I played with a Unity container and noticed strange behavior. I have a class that implements several interfaces. I want this class to be used in different places of the application with different lifetimes. So I mapped IFooDerived1 to Foo as Singleton, and IFooDerived2 to Foo as Transient. But any Foo posting corrupts previous Foo postings.

Example:

interface IFoo { } interface IFooDerived1 { } interface IFooDerived2 { } class Foo : IFoo, IFooDerived1, IFooDerived2 { } static void Main(string[] args) { var container = new UnityContainer(); container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); foreach(var r in container.Registrations) { Console.WriteLine("{0} -> {1} : {2}", r.RegisteredType.Name, r.MappedToType.Name, r.LifetimeManagerType.Name); } } 

Conclusion:

  IFoo -> Foo : TransientLifetimeManager IFooDerived1 -> Foo : TransientLifetimeManager IFooDerived2 -> Foo : TransientLifetimeManager 

Is this the right behavior? Can anyone give a logical explanation? I can easily use some other approach, I just want to understand why this is happening. Thanks.

+5
source share
1 answer

If you changed the registration to the following:

 container.RegisterType(typeof(IFooDerived1), typeof(Foo), new ContainerControlledLifetimeManager()); container.RegisterType(typeof(IFooDerived2), typeof(Foo), new TransientLifetimeManager()); container.RegisterType(typeof(IFoo), typeof(Foo), new ExternallyControlledLifetimeManager()); 

You will get the following result:

  IFoo -> Foo : ExternallyControlledLifetimeManager IFooDerived1 -> Foo : ExternallyControlledLifetimeManager IFooDerived2 -> Foo : ExternallyControlledLifetimeManager 

Wat? No matter what abstraction you extract, you will always have the same instance. Therefore, changing the order of registration, you get a completely different behavior in lifestyle.

btw, ExternallyControlledLifetimeManager scary like fuck because it uses a weak reference to the object and can recreate it after the application no longer stores the reference to It. You are unlikely to ever use this lifestyle.

I'm trying to figure this out, but it seems that in Unity, when you do the registration, you are actually registering an implementation with a certain lifestyle, and the provided abstraction just matches that registration. Therefore, if we define an alternative API for Unity, the registration will be something like this:

 MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); MapToEntry(from: typeof(IFoo), to: typeof(Foo)); 

So, with the help of this "alternative" API, it becomes clearer that the following happens:

 MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); MapToEntry(from: typeof(IFoo), to: typeof(Foo)); MakeEntry(typeof(Foo), new ExternallyControlledLifetimeManager()); MapToEntry(from: typeof(IFooDerived1), to: typeof(Foo)); MakeEntry(typeof(Foo), new TransientLifetimeManager()); MapToEntry(from: typeof(IFooDerived2), to: typeof(Foo)); 

This means that there are three entries for the same Foo , and apparently Unity just accepts this silence, and the latter wins. Don't you hate this implicit behavior?

Can I switch to another library?

+1
source

Source: https://habr.com/ru/post/1203332/


All Articles