public class MyService<br/>
{<br/>
[Dependency]<br/>
public Random MyRandom { get; set; }<br/>
}<br/>
<br/>
⋮<br/>
<br/>
var uc = new UnityContainer();<br/>
var svc = uc.Resolve<MyService>();<br/>
Console.WriteLine(svc.MyRandom.Next());<br/>
Attempting to create an object of type Random
through DI will fail because Random
has several constructors and Unity, despite the obviousness that it is necessary to call empty (ie, new Random()
) it does not, but tries to call the most "tricked" and suffers fiasco. How to fix this? Like this:
// Random
uc.RegisterType<Random>( new InjectionConstructor());<br/>
And if Random
was our class, it would be possible to write something like this:
class Random<br/>
{<br/>
[InjectionConstructor]<br/>
Random() { }<br/>
⋮<br/>
}<br/>
We just hinted to Unity to use an “empty” constructor. Well, let's try the new functionality:
var svc = uc.Resolve<MyService>();<br/>
var svc2 = uc.Resolve<MyService>();<br/>
Console.WriteLine(<br/>
ReferenceEquals(svc.MyRandom, svc2.MyRandom));<br/>
False
will be written to the console. default behavior of the container - every time create a new object. If you consider that one Random
-Millerovsky Random
should be enough for the whole project, then how to get a singleton? Yes, very simple:
uc.RegisterType<Random>(<br/>
new ContainerControlledLifetimeManager(),<br/>
new InjectionConstructor());<br/>
var svc = uc.Resolve<MyService>();<br/>
var svc2 = uc.Resolve<MyService>();<br/>
Console.WriteLine(<br/>
ReferenceEquals(svc.MyRandom, svc2.MyRandom));<br/>
This piece of code will already write to the console True
. A parameter inheriting from LifetimeManager
determines how long the object will live. It is useful to inherit from it if you want, for example, so that for each thread / session / call a new object is displayed.
public interface IService<br/>
{<br/>
int GetN();<br/>
}<br/>
<br/>
public class MyService : IService<br/>
{<br/>
public int n;<br/>
public MyService( int n)<br/>
{<br/>
this .n = n;<br/>
}<br/>
public int GetN() { return n; }<br/>
}<br/>
⋮<br/>
var uc = new UnityContainer();<br/>
uc.RegisterType<IService, MyService>();<br/>
uc.RegisterType< int >( new InjectionConstructor(10));<br/>
var svc = uc.Resolve<IService>();<br/>
Console.Write(svc.GetN());<br/>
Unfortunately, System.Int32
did not have a constructor, and therefore this code, which by the way is compiled without problems, will not work. In fact, we simply chose the wrong attribute — instead of manipulating the creation of Int32
, in this case, it is necessary to control the creation of IService
:
uc.RegisterType<IService, MyService>(<br/>
new InjectionConstructor(<br/>
new InjectionParameter(10)));<br/>
All these were fairly obvious constructor manipulations, let's look at an example more complicated. Suppose you have two services, and both implement IService
:
public interface IService<br/>
{<br/>
void DoSomething();<br/>
}<br/>
public class MyService : IService<br/>
{<br/>
public void DoSomething()<br/>
{<br/>
Console.WriteLine( "My service" );<br/>
}<br/>
}<br/>
public class OtherService : IService<br/>
{<br/>
public void DoSomething()<br/>
{<br/>
Console.WriteLine( "Other service" );<br/>
}<br/>
}<br/>
Now create a class that consumes these services:
public class Consumer<br/>
{<br/>
IService[] services;<br/>
public Consumer(IService[] services)<br/>
{<br/>
this .services = services;<br/>
}<br/>
public void DoEverything() <br/>
{<br/>
foreach ( var s in services)<br/>
s.DoSomething();<br/>
}<br/>
}<br/>
Attempting to kill Consumer
and call DoEverything
will not do anything - Unity has no idea that it would be nice to kill IService
as an exhaust of all registered types of IService
, and therefore will give new IService[0]
to the constructor. The container again has to help:
uc.RegisterType<Consumer>( new InjectionConstructor(<br/>
new ResolvedParameter<IService[]>()));<br/>
That's all for now. To be continued!Source: https://habr.com/ru/post/63280/