Reputation: 16499
I have a Xamarin.Forms
application where I am using Autofac for DI.
SO what I want is quite simple but I am unable to do something which seems like a sinch to do.
So I have a class that has two constructors both of them have a single parameter and based on certain conditions I want to resolve either one. As an example, I have a class A and what I want is based on conditions B or C should be resolved.
Eg:
public class A
{
public A(B bObject)
{...}
public A(C cObject)
{...}
}
But I am unable to understand how to do this. I tried doing something like below:
Registration:
builder.RegisterType<A>().
UsingConstructor(typeof(C)).
Named<A>(nameof(C));
builder.RegisterType<A>().
UsingConstructor(typeof(B)).
Named<A>(nameof(B));
Resolving:
DiContainer.ResolveNamed<A>(nameof(B));
DiContainer.ResolveNamed<A>(nameof(C));
Note: I have already Registered B and C in the container as shown below:
builder.RegisterType<B>();
builder.RegisterType<C>()
I am a little new to AutoFac and I am not even sure if this is the correct way, I think it has something to do with me registering it twice I am not sure.
Any suggestion or help is strongly appreciated.
Upvotes: 5
Views: 4070
Reputation: 23238
You can try to use an Autofac lambda registration for that and perform a registration using the following snippet (c
parameter here is IComponentContext
instance)
var builder = new ContainerBuilder();
builder.Register(
(c, p) =>
{
var condition = p.Named<bool>("condition");
return condition ? new A(c.Resolve<B>()) : new A(c.Resolve<C>());
});
builder.RegisterType<B>();
builder.RegisterType<C>();
Then resolve A
by passing a parameter to lambda expression. You can use TypedParameter
instead of named (constant values only) or ResolvedParameter
(dynamic values)
var a = container.Resolve<A>(new NamedParameter("condition", true));
If you don't want to explicitly call Resolve
, you can have a look at delegate factories (Func<T>
for example)
Upvotes: 1
Reputation: 14577
I believe you were very close, you literally needed to pass a Parameter
definition to your Resolve
public class B { }
public class C { }
public class A
{
public A(B bObject){ Console.WriteLine("I am constructor A typeof(B)");}
public A(C cObject){ Console.WriteLine("I am constructor A typeof(C)");}
}
void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<A>().UsingConstructor(typeof(B)).Named<A>(nameof(B));
builder.RegisterType<A>().UsingConstructor(typeof(C)).Named<A>(nameof(C));
//it doesn't really matter if these are registered as you're using nameof() to identify the objects - that's essentially string
builder.RegisterType<B>();
builder.RegisterType<C>();
var container = builder.Build();
var a1 = container.ResolveNamed<A>(nameof(B), new TypedParameter(typeof(B), new B()));
var a2 = container.ResolveNamed<A>(nameof(C), new TypedParameter(typeof(C), new C()));
}
Upvotes: 0
Reputation: 1110
Here is a simple workaround:
You can Wrap class B and C into another class which is then registered in autofac:
public class Wrapper {
public B BObject;
public C CObject;
}
You then can just do it a little bit like this (i dont know the correct way to resolve it as i dont have an IDE currently, but i hope you understand what iam doing here):
DiContainer.ResolveNamed<A>(new Wrapper(){BObject = Binstance});
Another solution:
What you can also do is registering B or C depending on what you want.
If you want that the class will be instantiated with B, register B on autofac, then resolve the class.
But the class needs to have two constructors. One with B as parameter and one with C ...
i think Autofac will resolve then depending on what got registered.
Upvotes: 0