简体   繁体   中英

Changing lowest level in dependency chain

In my project I have 5 classes:

  • ClassA (implements interface IClassA ), takes IClassC as constructor's argument
  • ClassB (implements interface IClassB ), takes IClassC as constructor's argument
  • ClassC (implements interface IClassC ), takes IClassD as constructor's argument
  • ClassD1 and ClassD2 (both implements interface IClassD )

Configuration of my Unity Container looks as follows:

    container.RegisterType<IClassA, ClassA>(new HierarchicalLifetimeManager());
    container.RegisterType<IClassB, ClassB>(new HierarchicalLifetimeManager());
    container.RegisterType<IClassC, ClassC>(new HierarchicalLifetimeManager());
    container.RegisterType<IClassD, ClassD1>(nameof(ClassD1), new HierarchicalLifetimeManager());
    container.RegisterType<IClassD, ClassD2>(nameof(ClassD2), new HierarchicalLifetimeManager());

I would like to configure my project, that:

  • IClassA is using ClassC which is using ClassD1
  • IClassB is using ClassC which is using ClassD2

I'm guesing that I should change something in registration of IClassA and IClassB . I would like to avoid to change IClassC registration.

Is that possible?

I don't know the exact reason why you want to do this but it is possible with the help of a factory.

Although it works, I would potentially review the design and the circumstances because it is complex and it confuses developers (it smells).

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<IClassC, ClassC>();
        container.RegisterType<IClassD, ClassD1>(nameof(ClassD1), new HierarchicalLifetimeManager());
        container.RegisterType<IClassD, ClassD2>(nameof(ClassD2), new HierarchicalLifetimeManager());
        container.RegisterType<IClassA, ClassA>(new InjectionConstructor(Factory.GetClassC<ClassD1>(container)));
        container.RegisterType<IClassB, ClassB>(new InjectionConstructor(Factory.GetClassC<ClassD2>(container)));

        var classA = container.Resolve<IClassA>();
        var classB = container.Resolve<IClassB>();

        classA.HelloFromA();
        classB.HelloFromB();
    }
}

public class Factory
{
    public static IClassC GetClassC<TClassD>(IUnityContainer container)
        where TClassD : IClassD
    {
        return container.Resolve<IClassC>(new DependencyOverride<IClassD>(
            container.Resolve<IClassD>(typeof(TClassD).Name)));
    }
}

public interface IClassA
{
    void HelloFromA();
}

public interface IClassB
{
    void HelloFromB();
}

public interface IClassC
{
    void HelloFromC();
}

public interface IClassD { }

public class ClassA : IClassA
{
    private readonly IClassC _classC;
    public ClassA(IClassC classC)
    {
        _classC = classC;
    }
    public void HelloFromA()
    {
        _classC.HelloFromC();
    }
}

public class ClassB : IClassB
{
    private readonly IClassC _classC;
    public ClassB(IClassC classC)
    {
        _classC = classC;
    }

    public void HelloFromB()
    {
        _classC.HelloFromC();
    }
}

public class ClassC : IClassC
{
    private readonly IClassD _classD;
    public ClassC(IClassD classD)
    {
        _classD = classD;
    }

    public void HelloFromC()
    {
        Console.WriteLine(string.Format("Hello with {0}", _classD.GetType().Name));
    }
}

public class ClassD1 : IClassD
{
}

public class ClassD2 : IClassD
{
}

Things to note:

  1. Notice the order of registration. ClassA and ClassB are registered at the end,
  2. HierarchicalLifetimeManager cannot be used in this instance as you need 2 different instances of the same class.

Consider reading this article: http://sharpfellows.com/post/Unity-IoC-Container-

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM