-
Notifications
You must be signed in to change notification settings - Fork 29
Is it possible to create an object with parameters for each Resolve in a dependency registered in transient? #30
-
I am currently interested in Pure.DI for its excellent performance.
I have a question regarding functionality.
Is it possible to create an object with parameters for each Resolve in a dependency registered in transient?
Below is the code I would like to use as follows:
interface IDependency { }
class Dependency : IDependency { }
interface IService
{
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
class Service : IService
{
public Service(
IDependency dependency1,
IDependency dependency2,
string param1, // <----(1)
int param2) // <----(2)
{
Dependency1 = dependency1;
Dependency2 = dependency2;
Param1 = param1;
Param2 = param2;
}
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
DI.Setup("Composition")
.Bind<IDependency>().As(Lifetime.Transient).To<Dependency>()
.Bind<IService>().To<Service>().Root<IService>("Root");
var composition = new Composition();
var service1 = composition.Resolve<IService>("ABC", 123); // <---(A)
var service2 = composition.Resolve<IService>("XYZ", 789); // <---(B)
Beta Was this translation helpful? Give feedback.
All reactions
I have published a beta package and added the RootArg method. Please see the example here. Now you can create composition roots with arguments. And your example can be rewritten like this:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService"); interface IDependency { } class Dependency : IDependency { } interface I...
Replies: 13 comments 7 replies
-
@YoshihiroIto thank you for your interest in this project.
The problem you have raised is quite well known. The point is that there is no easy way to use the constructor injection together with the manual state passing there. Some tricks are always required.
The simplest solution is to leave the constructor to DI, and use properties or a special method, for example called Initialize, to pass the state manually. In this case the object will not be fully initialized for some short time.
Another option is to use a special "factory" class, which will create objects. In order not to create such an "factory" class, you can use System.Func<> instead as in the example below:
using Pure.DI; var composition = new Composition(); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .Bind<Func<string, int, IService>>().As(Lifetime.Singleton).To<Func<string, int, IService>>(ctx => (param1, param2) => { ctx.Inject<IDependency>(out var dep1); ctx.Inject<IDependency>(out var dep2); return new Service(dep1, dep2, param1, param2); }) .Root<Func<string, int, IService>>("CreateService"); var factory = composition.Resolve<Func<string, int, IService>>(); var service1 = factory("ABC", 123); // <---(A) var service2 = factory("XYZ", 789); // <---(B) // But better is just: var service3 = composition.CreateService("ABC", 123); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, string param1, // <----(1) int param2) // <----(2) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } }
In this case, the code is still effective:
public Func<string, int, IService> CreateService { get { if (Object.ReferenceEquals(_singletonM08D06di23, null)) { lock (_disposableSingletonsM08D06di) { if (Object.ReferenceEquals(_singletonM08D06di23, null)) { _singletonM08D06di23 = (param1, param2) => { return new Service(new Dependency(), new Dependency(), param1, param2); }; } } } return _singletonM08D06di23; } }
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you for your answer.
I appreciate your solution as well as the knowledge that this problem is well known.
I will try to use the "factory" class.
Here is what I would like to do.
Bind<Func<string, int, IService>>().As(Lifetime.Singleton).To<Func<string, int, IService>>(ctx => (param1, param2) =>
{
ctx.Inject<IDependency>(out var dep1);
ctx.Inject<IDependency>(out var dep2);
return new Service(dep1, dep2, param1, param2);
})
I worry that this part needs to be declared for each class.
I felt that it would be better if a simple declaration could be used to generate the code for this part as well.
For example,
https://github.com/DevTeam/Pure.DI/blob/master/readme/arguments.md
This is a mechanism for composition generation, but we would like to be able to declare it this way.
Thank you.
Beta Was this translation helpful? Give feedback.
All reactions
-
This sample essentially prepends external singleton objects to the generated classes. You really need "external PerResolve" objects.
Some time ago I thought of making similar arguments for each root of a composition. But unfortunately it would not work well for Resolve methods. Thanks for giving me the idea, it's an important use case after all. I'll try to figure out how to do it.
Take a look at this example, but it's also quite workable:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService("ABC", 123); // <---(A) var service2 = composition.CreateService("XYZ", 789); // <---(B) partial class Composition { [ThreadStatic] private static string _param1; [ThreadStatic] private static int _param2; private static void Setup() => DI.Setup(nameof(Composition)) .Bind<IDependency>().To<Dependency>() .Bind<string>("param1").To(_ => _param1) .Bind<int>("param2").To(_ => _param2) .Bind<IService>().To<Service>() .Root<IService>("ServiceRoot"); public IService CreateService(string param1, int param2) { _param1 = param1; _param2 = param2; return ServiceRoot; } } interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, [Tag("param1")] string param1, // <----(1) [Tag("param2")] int param2) // <----(2) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } }
Beta Was this translation helpful? Give feedback.
All reactions
-
👀 1
-
I have published a beta package and added the RootArg method. Please see the example here. Now you can create composition roots with arguments. And your example can be rewritten like this:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, string param1, // <----(1) int param2) // <----(2) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } }
Please try it and tell me how convenient this API is.
Beta Was this translation helpful? Give feedback.
All reactions
-
Your work is excellent.
I have verified that the sample you provided works correctly.
I modified the sample slightly and tried it out.
What if I need to have multiple service creators and each service has a different parameter type but the same name?
I tried the following code. And it worked. Is this a correct usage of the Pure.DI specification?
using Pure.DI;
using System.Diagnostics;
var composition = new Composition();
var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A)
var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B)
var otherService1 = composition.CreateOtherService(param1: new object(), param2: typeof(int));
var otherService2 = composition.CreateOtherService(param1: "vvv", param2: typeof(float));
Debug.WriteLine(otherService1);
DI.Setup("Composition")
.Bind<IDependency>().To<Dependency>()
.RootArg<string>("param1")
.RootArg<int>("param2")
.Bind<IService>().To<Service>().Root<IService>("CreateService")
.RootArg<object>("param1")
.RootArg<Type>("param2")
.Bind<IOtherService>().To<OtherService>().Root<IOtherService>("CreateOtherService");
interface IDependency { }
class Dependency : IDependency { }
interface IService
{
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
class Service : IService
{
public Service(
IDependency dependency1,
IDependency dependency2,
string param1, // <----(1)
int param2) // <----(2)
{
Dependency1 = dependency1;
Dependency2 = dependency2;
Param1 = param1;
Param2 = param2;
}
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
interface IOtherService
{
object Param1 { get; }
Type Param2 { get; }
}
class OtherService : IOtherService
{
public OtherService(
object param1,
Type param2)
{
Param1 = param1;
Param2 = param2;
}
public object Param1 { get; }
public Type Param2 { get; }
}
Beta Was this translation helpful? Give feedback.
All reactions
-
I'm glad it worked for your scenario. You used the API correctly.
But another case is interesting when you have 2 different arguments of the same type. Then it is recommended to use tags to specify the correspondence, for example:
using Pure.DI; using System.Diagnostics; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123, param3: "aaaa"); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789, param3: "bbbb"); // <---(B) var otherService1 = composition.CreateOtherService(param1: new object(), param2: typeof(int)); var otherService2 = composition.CreateOtherService(param1: "vvv", param2: typeof(float)); Debug.WriteLine(otherService1); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService") .RootArg<object>("param1") .RootArg<Type>("param2") .Bind<IOtherService>().To<OtherService>().Root<IOtherService>("CreateOtherService") .RootArg<string>("param3", "another string"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, string param1, // <----(1) int param2, // <----(2) [Tag("another string")] string param3) // <----(3) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } interface IOtherService { object Param1 { get; } Type Param2 { get; } } class OtherService : IOtherService { public OtherService( object param1, Type param2) { Param1 = param1; Param2 = param2; } public object Param1 { get; } public Type Param2 { get; } }
Tags allow you to work on the same type, but distinguish between them guided by custom logic, please pay attention to the constructor parameter [Tag("another string")] string param3.
Beta Was this translation helpful? Give feedback.
All reactions
-
👀 1
-
Thank you for responding to my many requests.
Is it possible to specify the relationship between arguments and route names by attributes?
If so, I thought it would be possible to automatically resolve the argument information as well.
There is an advantage to having the class definition and the relationship between the constructor arguments in one place.
In addition, class declarations are made in multiple assemblies.
Also, I have had some experience in the past when I developed an application with many developers participating, and I had a conflict problem in the part of registering classes to a DI container.
In the case of Pure.DI.
DI.Setup("Composition")
...
...
...
...
The advantage is that registered classes can be seen at a glance, but because they are concentrated in one place, it was difficult to avoid conflicts when many developers participate.
The following is my imagination.
using Pure.DI;
var composition = new Composition();
var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A)
var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B)
var otherService1 = composition.CreateOtherService(param1: new object(), param2: typeof(int));
var otherService2 = composition.CreateOtherService(param1: "vvv", param2: typeof(float));
DI.Setup("Composition")
.Bind<IDependency>().To<Dependency>();
interface IDependency { }
class Dependency : IDependency { }
interface IService
{
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
class Service : IService
{
[Root<IService>(Name="CreateService"))] // <---
public Service(
IDependency dependency1,
IDependency dependency2,
string param1, // <----(1)
int param2) // <----(2)
{
Dependency1 = dependency1;
Dependency2 = dependency2;
Param1 = param1;
Param2 = param2;
}
[Root<IService>(Name="CreateService"))] // <---
public Service(
IDependency dependency1,
IDependency dependency2)
{
Dependency1 = dependency1;
Dependency2 = dependency2;
Param1 = "default";
Param2 = -1;
}
public IDependency Dependency1 { get; }
public IDependency Dependency2 { get; }
public string Param1 { get; }
public int Param2 { get; }
}
interface IOtherService
{
object Param1 { get; }
Type Param2 { get; }
}
class OtherService : IOtherService
{
[Root<IOtherService>(Name="CreateOtherService"))] // <---
public OtherService(
object param1,
Type param2)
{
Param1 = param1;
Param2 = param2;
}
public object Param1 { get; }
public Type Param2 { get; }
}
Beta Was this translation helpful? Give feedback.
All reactions
-
Unfortunately attributes are not supported right now. They have too many limitations. But it is possible in the future.
But even now you can split the DI setup to avoid conflicts as in the example below:
using Pure.DI; using System.Diagnostics; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123, param3: "aaaa"); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789, param3: "bbbb"); // <---(B) var otherService1 = composition.CreateOtherService(param1: new object(), param2: typeof(int)); var otherService2 = composition.CreateOtherService(param1: "vvv", param2: typeof(float)); Debug.WriteLine(otherService1); interface IDependency { } class Dependency : IDependency { private void Setup() => DI.Setup("Composition") .Bind<IDependency>().To<Dependency>(); } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, string param1, // <----(1) int param2, // <----(2) [Tag("another string")] string param3) // <----(3) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } private void Setup() => DI.Setup("Composition") .RootArg<string>("param1") .RootArg<int>("param2") .RootArg<string>("param3", "another string") .Bind<IService>().To<Service>() .Root<IService>("CreateService"); } interface IOtherService { object Param1 { get; } Type Param2 { get; } } class OtherService : IOtherService { public OtherService( object param1, Type param2) { Param1 = param1; Param2 = param2; } public object Param1 { get; } public Type Param2 { get; } private void Setup() => DI.Setup("Composition") .RootArg<object>("param1") .RootArg<Type>("param2") .Bind<IOtherService>().To<OtherService>() .Root<IOtherService>("CreateOtherService"); }
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
I understand attribute is not currently supported. I look forward to your future work.
And thank you for your help in presenting specific ways to avoid conflicts.
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi! @NikolayPianikov
It has been a long period of time, I am currently using your Pure.DI to develop my application. Thank you very much.
I am having trouble with the RootArg that you previously told us about in this discussion, as I am getting errors in some cases.
I have made some changes to the sample code I used before. The following code does not generate the correct CreateService method and results in a compile error.
I think the cause is my lack of understanding. Please let me know what is wrong with this code.
using Pure.DI; using System.Diagnostics; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) var otherService1 = composition.CreateOtherService(param3: new object(), param4: typeof(int), param5: service1); var otherService2 = composition.CreateOtherService(param3: "vvv", param4: typeof(float), param5: service2); Debug.WriteLine(otherService1); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService") .RootArg<object>("param3") .RootArg<Type>("param4") .RootArg<IService>("param5") .Bind<IOtherService>().To<OtherService>().Root<IOtherService>("CreateOtherService"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } class Service : IService { public Service( IDependency dependency1, IDependency dependency2, string param1, int param2) { Dependency1 = dependency1; Dependency2 = dependency2; Param1 = param1; Param2 = param2; } public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Param1 { get; } public int Param2 { get; } } interface IOtherService { object Param3 { get; } Type Param4 { get; } IService Param5 { get; } } class OtherService : IOtherService { public OtherService( object param3, Type param4, IService param5) { Param3 = param3; Param4 = param4; Param5 = param5; } public object Param3 { get; } public Type Param4 { get; } public IService Param5 { get; } }
Beta Was this translation helpful? Give feedback.
All reactions
-
@YoshihiroIto. you can always find the generated code in the project, for example:
It is useful to understand how object compositions are created.
The problem was that you defined the IService dependency
.Bind<IService>().To<Service>().Root<IService>("CreateService")
as an argument .RootArg<IService>("param5").
In other words: the creation of the .Bind<IService>() binding was overridden by declaring the root argument .RootArg<IService>("param5")
Perhaps you meant:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) Console.WriteLine(service1); Console.WriteLine(service2); var otherService1 = composition.CreateOtherService(param1: "Abc", param2: 99, param3: new object(), param4: typeof(string)); var otherService2 = composition.CreateOtherService(param1: "Xyz", param2: 33, param3: new object(), param4: typeof(double)); Console.WriteLine(otherService1); Console.WriteLine(otherService2); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService") .RootArg<object>("param3") .RootArg<Type>("param4") .Bind<IOtherService>().To<OtherService>().Root<IOtherService>("CreateOtherService"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Text { get; } public int Id { get; } } record Service( IDependency Dependency1, IDependency Dependency2, string Text, int Id) : IService; interface IOtherService { object MyObject { get; } Type SomeType { get; } IService MyService { get; } } record OtherService( object MyObject, Type SomeType, IService MyService): IOtherService;
I also changed the type on the records to output the stdOut values of the properties. And changed the field names to make it look better.
stdOut:
Service { Dependency1 = Dependency, Dependency2 = Dependency, Text = ABC, Id = 123 }
Service { Dependency1 = Dependency, Dependency2 = Dependency, Text = XYZ, Id = 789 }
OtherService { MyObject = System.Object, SomeType = System.String, MyService = Service { Dependency1 = Dependency, Dependency2 = Dependency, Text = Abc, Id = 99 } }
OtherService { MyObject = System.Object, SomeType = System.Double, MyService = Service { Dependency1 = Dependency, Dependency2 = Dependency, Text = Xyz, Id = 33 } }
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you for presenting the sample code.
But my question is not solved.
The generated code from your sample creates a new IService instance in CreateOtherService.
I want to store the IService instance passed in the argument of CreateOtherService in MyService.
This is the source code I would like you to generate. Is it possible to achieve this result?
#region Composition Roots [global::System.Runtime.CompilerServices.MethodImpl((global::System.Runtime.CompilerServices.MethodImplOptions)0x300)] public IService CreateService(string param1, int param2) { var transientM11D18di2 = new Dependency(); var transientM11D18di1 = new Dependency(); var transientM11D18di0 = new Service(transientM11D18di1, transientM11D18di2, param1, param2); return transientM11D18di0; } [global::System.Runtime.CompilerServices.MethodImpl((global::System.Runtime.CompilerServices.MethodImplOptions)0x300)] public IOtherService CreateOtherService(System.Type param4, object param3, IService param5) { var transientM11D18di0 = new OtherService(param3, param4, param5); return transientM11D18di0; } #endregion
Beta Was this translation helpful? Give feedback.
All reactions
-
@YoshihiroIto In this case, it makes no sense for you to make bindings for the roots of the composition:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) Console.WriteLine(service1); Console.WriteLine(service2); var otherService1 = composition.CreateOtherService(param3: new object(), param4: typeof(string), param5: service1); var otherService2 = composition.CreateOtherService(param3: new object(), param4: typeof(double), param5: service2); Console.WriteLine(otherService1); Console.WriteLine(otherService2); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Root<Service>("CreateService") .RootArg<object>("param3") .RootArg<Type>("param4") .RootArg<IService>("param5") .Root<OtherService>("CreateOtherService"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Text { get; } public int Id { get; } } record Service( IDependency Dependency1, IDependency Dependency2, string Text, int Id) : IService; interface IOtherService { object MyObject { get; } Type SomeType { get; } IService MyService { get; } } record OtherService( object MyObject, Type SomeType, IService MyService): IOtherService;
And the generated code will be like this:
public Service CreateService(string param1, int param2) { var transientM11D18di2 = new Dependency(); var transientM11D18di1 = new Dependency(); var transientM11D18di0 = new Service(transientM11D18di1, transientM11D18di2, param1, param2); return transientM11D18di0; } public OtherService CreateOtherService(System.Type param4, object param3, IService param5) { var transientM11D18di0 = new OtherService(param3, param4, param5); return transientM11D18di0; }
Beta Was this translation helpful? Give feedback.
All reactions
-
It will be necessary to make some sorting of parameters, and now some kind of disorder :) Probably better in the order in which they're defined ...
Beta Was this translation helpful? Give feedback.
All reactions
-
I would like to handle the return types of the generated CreateService and CreateOtherService in the interface.
I want to handle the type to be implemented in the interface without exposing it to the outside world.
Is it possible to generate the following code?
public IService CreateService(string param1, int param2) { var transientM11D18di2 = new Dependency(); var transientM11D18di1 = new Dependency(); var transientM11D18di0 = new Service(transientM11D18di1, transientM11D18di2, param1, param2); return transientM11D18di0; } public IOtherService CreateOtherService(System.Type param4, object param3, IService param5) { var transientM11D18di0 = new OtherService(param3, param4, param5); return transientM11D18di0; }
Beta Was this translation helpful? Give feedback.
All reactions
-
@YoshihiroIto, root arguments are just another kind of binding. To make it work as you expect you need to distinguish them for different bindings. Your code .RootArg<IService>("param5") overrides the binding .Bind<IService>().To<Service>():
DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>().To<Service>().Root<IService>("CreateService") .RootArg<object>("param3") .RootArg<Type>("param4") // overrides .Bind<IService>().To<Service>().Root<IService>("CreateService") .RootArg<IService>("param5") .Bind<IOtherService>().To<OtherService>().Root<IOtherService>("CreateOtherService");
And then the Service root is simply taken from the function argument "param5".
You need to prevent the .Bind<IService>().To<Service() binding from being overridden by the .RootArg<IService>("param5") binding. Since type alone in this case will not be enough to distinguish between these two bindings, you can use arbitrary tags. And the settings could look something like this:
using Pure.DI; var composition = new Composition(); var service1 = composition.CreateService(param1: "ABC", param2: 123); // <---(A) var service2 = composition.CreateService(param1: "XYZ", param2: 789); // <---(B) Console.WriteLine(service1); Console.WriteLine(service2); var otherService1 = composition.CreateOtherService(param3: new object(), param4: typeof(string), param5: service1); var otherService2 = composition.CreateOtherService(param3: new object(), param4: typeof(double), param5: service2); Console.WriteLine(otherService1); Console.WriteLine(otherService2); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .RootArg<int>("param2") .Bind<IService>("root only").To<Service>() .Root<IService>("CreateService", "root only") .RootArg<object>("param3") .RootArg<Type>("param4") .RootArg<IService>("param5") .Bind<IOtherService>("also root-only").To<OtherService>() .Root<IOtherService>("CreateOtherService", "also root-only"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Text { get; } public int Id { get; } } record Service( IDependency Dependency1, IDependency Dependency2, string Text, int Id) : IService; interface IOtherService { object MyObject { get; } Type SomeType { get; } IService MyService { get; } } record OtherService( object MyObject, Type SomeType, IService MyService): IOtherService;
And the generated code will be like this:
public IService CreateService(string param1, int param2) { var transientM11D18di2 = new Dependency(); var transientM11D18di1 = new Dependency(); var transientM11D18di0 = new Service(transientM11D18di1, transientM11D18di2, param1, param2); return transientM11D18di0; } public IOtherService CreateOtherService(System.Type param4, object param3, IService param5) { var transientM11D18di0 = new OtherService(param3, param4, param5); return transientM11D18di0; }
Beta Was this translation helpful? Give feedback.
All reactions
-
Thanks for the sample code.
I have acknowledged that this works correctly. I don't fully understand it yet, but I will incorporate it into my product to better understand it.
Beta Was this translation helpful? Give feedback.
All reactions
-
.Bind<IService>("root only").To<Service>()
Defines the binding of an IService to a Service with the tag "root only". Where the binding key is actually (IService, "root only").
.Root<IService>("CreateService", "root only")
Creates a root named "CreateService" that relies on the binding (IService, "root only").
Therefore, the .Bind<IService>("root only").To<Service>() binding is not overridden by the .RootArg<IService>("param5") binding because .RootArg<IService>("param5") does not contain a tag and its actual key is (IService, null).
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you for the detailed explanation.
I have solved this problem and successfully used Pure.DI in my project.
I had one other problem that I could not solve.
I tried to use the same tag for Arg() to resolve the binding, but was unable to do so.
https://github.com/DevTeam/Pure.DI/blob/master/readme/arguments.md
However, I made a simple sample program and tried it, and it works fine, so I think it is either a problem with my project or my lack of understanding.
Beta Was this translation helpful? Give feedback.
All reactions
-
I tried to use the same tag for Arg() to resolve the binding, but was unable to do so. https://github.com/DevTeam/Pure.DI/blob/master/readme/arguments.md
I didn't get the point of the problem with Arg. If it is relevant, you could send a sample of your code and expected behavior.
Arg should work like RootArg, only the arguments are passed through the class constructor and are available in all roots. For unstance:
using Pure.DI; var composition = new Composition(param2: 123); var service1 = composition.CreateService(param1: "ABC"); // <---(A) var service2 = composition.CreateService(param1: "XYZ"); // <---(B) Console.WriteLine(service1); Console.WriteLine(service2); var otherService1 = composition.CreateOtherService(param3: new object(), param4: typeof(string), param5: service1); var otherService2 = composition.CreateOtherService(param3: new object(), param4: typeof(double), param5: service2); Console.WriteLine(otherService1); Console.WriteLine(otherService2); Console.WriteLine(composition); DI.Setup("Composition") .Bind<IDependency>().To<Dependency>() .RootArg<string>("param1") .Arg<int>("param2") .Bind<IService>("root only").To<Service>() .Root<IService>("CreateService", "root only") .RootArg<object>("param3") .RootArg<Type>("param4") .RootArg<IService>("param5") .Bind<IOtherService>("also root-only").To<OtherService>() .Root<IOtherService>("CreateOtherService", "also root-only"); interface IDependency { } class Dependency : IDependency { } interface IService { public IDependency Dependency1 { get; } public IDependency Dependency2 { get; } public string Text { get; } public int Id { get; } } record Service( IDependency Dependency1, IDependency Dependency2, string Text, int Id) : IService; interface IOtherService { object MyObject { get; } Type SomeType { get; } IService MyService { get; } } record OtherService( object MyObject, Type SomeType, IService MyService): IOtherService;
Beta Was this translation helpful? Give feedback.