FreakyAli
FreakyAli

Reputation: 16499

Autofac resolve the same class instance with different parameters

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

Answers (3)

Pavel Anikhouski
Pavel Anikhouski

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

timur
timur

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

Loading
Loading

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

Related Questions