0

I have 2 classes that implement IMyInterface, lets call them ClassA and ClassB. The problem here is that ClassA also needs IMyInterface, which should be the implementation of ClassB. And there's ClassConsumer which should use ClassA (the one who is IMyInterface and depends on IMyInterface)

Is there a way to do something like?:

var container = new UnityContainer();

//... several others registrations 

container.RegisterType<ITransactionProcessingService, ClassConsumer>();

var specialRegistrationForIMyInterface = _container.RegisterType<IMyInterface, ClassB>();
container.RegisterType<IMyInterface, ClassA>(specialRegistrationForIMyInterface);

Code Samples:

public interface IMyInterface
{
    void PushToDatabase();
}

public class ClassA : IMyInterface
{
    IMyInterface _IMyInterface;
    public ClassA(IMyInterface myInterface)
    {
        _IMyInterface = myInterface;
    }

    public void PushToDatabase()
    {
        //do other stuff
        //BusinessCheck();
        //Log();
        //Cache();
        _IMyInterface.PushToDatabase();
    }
}

public class ClassB : IMyInterface
{
    public void PushToDatabase()
    {
        //Actual insert on database
    }
}

Edit 2: Code after Progman suggestion:

var container = new UnityContainer();

//... several others registrations 

container.RegisterType<IMyInterface, ClassB>("Foo");
container.RegisterType<IMyInterface, ClassA>("Bar", new InjectionConstructor(new ResolvedParameter<IMyInterface>("Foo")));


container.RegisterType<ITransactionProcessingService, ClassConsumer>(new InjectionConstructor(new ResolvedParameter<IMyInterface>("Bar")));

and I get an error "No member matching data has been found."

Leonardo
  • 10,737
  • 10
  • 62
  • 155
  • What do you mean by "should be the implementation of `ClassB`"? How do you know that it is `ClassB` you are looking for? What makes `ClassB` different to `ClassA` to decide that `ClassB` should be injected and not `ClassB` when `IMyInterface` is requested? – Progman May 14 '20 at 20:34
  • 2
    Does this answer your question? [Resolving wrapper classes in C# with the Unity IoC container](https://stackoverflow.com/questions/1989299/resolving-wrapper-classes-in-c-sharp-with-the-unity-ioc-container) – orhtej2 May 14 '20 at 20:40
  • @Progman not exctlay like that but close – Leonardo May 14 '20 at 20:43
  • @orhtej2 not exactly like that but also close – Leonardo May 14 '20 at 20:43
  • @Progman check edit 2... its not working as expected – Leonardo May 14 '20 at 20:59
  • @Leonardo Please provide a [mcve], which shows the error message you get and which can be compiled and tested by others. – Progman May 14 '20 at 21:46

1 Answers1

1

You can use InjectionConstructor to provide additional information for the constructor. Use it with ResolveParameter to specify which specific instance you want to inject. Assume you have the following classes and interface:

public interface IMyInterface
{
    void PushToDatabase();
}

public class ClassA : IMyInterface
{
    public ClassA(IMyInterface myInterface)
    {
        Console.WriteLine("Constructor of ClassA was injected with: "+myInterface);
    }

    public void PushToDatabase()
    {
    }
}

public class ClassB : IMyInterface
{
    public void PushToDatabase()
    {
        //Actual insert on database
    }
}

public class ClassC : IMyInterface
{
    public void PushToDatabase()
    {
        //Actual insert on database
    }
}
public class ClassD : IMyInterface
{
    public void PushToDatabase()
    {
        //Actual insert on database
    }
}

There are four possible implementations. You can register all of them, but for the class ClassA you can specify which instance you want to inject.

var container = new UnityContainer();

container.RegisterType<IMyInterface, ClassB>();
container.RegisterType<IMyInterface, ClassC>();
container.RegisterType<IMyInterface, ClassA>(new InjectionConstructor(new ResolvedParameter(typeof(ClassB))));
container.RegisterType<IMyInterface, ClassD>();

Registering the types like this means "For the class ClassA use an instance of ClassB for the IMyInterface argument." When you execute the following code:

var classA = container.Resolve<ClassA>();
Console.WriteLine("Resolved to: "+classA);

var myInterface = container.Resolve<IMyInterface>();
Console.WriteLine("Resolved to: "+myInterface);

You will get the following output:

Constructor of ClassA was injected with: ClassB
Resolved to: ClassA
Resolved to: ClassD

As you see, the ClassA object was injected with a ClassB object. You also see, that when you request IMyInterface you get the last registered type, in this case it's ClassD.

Progman
  • 16,827
  • 6
  • 33
  • 48
  • I implemented what you suggested above and im still getting "No member matching data has been found." – Leonardo May 14 '20 at 21:06
  • @Leonardo Not sure it is is required for you to use names for the registrations, but using names [works as well](https://dotnetfiddle.net/Xx5VEq). – Progman May 14 '20 at 21:13
  • idk why, but its just not working... on the first register type using the `ResolvedParameter` or `ResolvedParameter` I get the error as if I had not `RegisterType` previously – Leonardo May 14 '20 at 21:42
  • I had to add the resolver for each of the parameters of the constructor, not only the one I wish to customize – Leonardo May 14 '20 at 22:29