-1

I love the idea of Dependency Injection (DI) but I always run into a wall when I try to use DI in a real world example. While processing within an instance of a class (MyParentClass) I often want to pass any "Special" processing to an instance of a class (MyChildClass). Often I want to use a DI instance(MyStringManipulator) within that child class. The only working way I have found to accomplish this is by passing that DI instance (MyStringManipulator) through the whole chain of parent->child instances within my class library. Seems like there should be an easier/better way. Thank You for your help.

public class MyParentClass
{
   public string ManipulateString( string s)
   {
      MyChildClass my = new MyChildClass();
      return my.Process(s);
   }
}

public class MyChildClass
{
   MyStringManipulator _manipulator = null;
   public MyChildClass (MyStringManipulator manipulator )
   {
      _manipulator = manipulator;
   }
   public string Process( string s)
   {
      return _manipulator.Manipulate(s);
   }
}
  • 2
    Have you considered to also inject `MyChildClass` into `MyParentClass` ? – Fildor Jun 29 '21 at 11:08
  • If parent and child are just passing the variable along (just based on your simplified chain example), then `MyStringManipulator` is what should actually be explicitly injected where needed. – Nkosi Jun 29 '21 at 11:22
  • Thanks @Fildor. How would that would help. These classes are in a Class Library. At some point along the way a DI needs to happen from within the Class Library. – Kelly Harris Jun 29 '21 at 11:25
  • Exactly @Nkosi, thanks. That is the crux of the question. – Kelly Harris Jun 29 '21 at 11:27
  • @KellyHarris, Fildor is correct about injecting child into parent. avoid manually initializing dependencies to avoid tight coupling. It does not matter if this is a class library. what ever is consuming the class library will be responsible for the composition of the classes in the library – Nkosi Jun 29 '21 at 11:28
  • 1
    If you are wondering how to setup DI, you can add an extension method to your library that sets up DI for dependencies inside the library. In the consuming app, you then do something like `services.AddMySuperDuperLibrary();` and that's it. ( I am assuming you are using MS Dependency Injection , but it would also be possible to make it work with other container frameworks like Ninject or AutoFac) – Fildor Jun 29 '21 at 11:34
  • Thanks @Fildor. I understand how to set up DI. It is the use of the DI that seems not to be complete – Kelly Harris Jun 29 '21 at 11:46
  • 1
    @KellyHarris based on provided answers there appears to be some confusion about what it is you are asking. So I suggest you edit the question to clarify things – Nkosi Jun 29 '21 at 11:50
  • In a Class Library, how does a "child" class instance get the "instance" of ILogger – Kelly Harris Jun 29 '21 at 11:53
  • 1
    Just have it as a constructor argument. Every thing should be configured and passed in the composition root. I think you are focusing on the wrong things or are confused about how to apply DI. – Nkosi Jun 29 '21 at 11:54
  • Thanks @Nkosi. I see I was not clear enough. – Kelly Harris Jun 29 '21 at 11:55
  • 1
    See: [Understanding the Composition Root](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/). – Steven Jun 29 '21 at 12:04
  • @Nkosi- "public MyChildClass (MyStringManipulator manipulator )" does not work. Are you saying that I should pass in a "dozen" of instances because I might use them in some class' instance? Do I keep passing all "dozen" to every class I instantiate? Thanks – Kelly Harris Jun 29 '21 at 12:04
  • Thanks @Steven. How does this help? "Only applications should have Composition Roots. Libraries and frameworks shouldn't.". I am working with a "Class Library" – Kelly Harris Jun 29 '21 at 12:08
  • 1
    @KellyHarris: But your class library will be used in an application, right? That application (the startup project) will contain the Composition Root where all classes (including the classes of your library) will get composed. – Steven Jun 29 '21 at 12:10
  • @KellyHarris I believe that is your confusion. You are focusing solely on the library/framework. Some thing has to use the library/framework. That something is what will be responsible for setting up the DI. Once you design your types within the library/framework following a proper SOLID design, which includes DI then it does not matter that it is a library. – Nkosi Jun 29 '21 at 12:10
  • @Nkosi, the Class Library is where my issue is. What should I focus on? The Class Library is what I have created because of SOLID. Should everyone put all of their classes within the main APP? – Kelly Harris Jun 29 '21 at 12:15
  • Does this answer your question? https://stackoverflow.com/a/2047657/126014 – Mark Seemann Jun 29 '21 at 12:29

1 Answers1

1

You should inject your child class in your parent class so you can apply you normal DI architecture. But note that in case you are stacking to many injections into one class your class is probably doing to much.

public class MyParentClass
{
   private readonly MyChildClass _my;
   
   public MyParentClass(MyChildClass my)
   {
      _my = my;
   }
   
   public string ManipulateString(string s)
   {
      return _my.Process(s);
   }
}

public class MyChildClass
{
   MyStringManipulator _manipulator = null;

   public MyChildClass (MyStringManipulator manipulator)
   {
      _manipulator = manipulator;
   }

   public string Process(string s)
   {
      return _manipulator.Manipulate(s);
   }
}
René
  • 100
  • 1
  • 8
  • Thanks @Rene but this does not answer the question. – Kelly Harris Jun 29 '21 at 11:40
  • @KellyHarris Why doesn't it? What your question, then? – Mark Seemann Jun 29 '21 at 12:30
  • @Rene, I should have explained my response. If I have a possibility of a dozen different possible DI instances, I do not want to have to pass all dozen around. Thanks – Kelly Harris Jun 29 '21 at 12:33
  • 2
    @KellyHarris Do all child objects need *all* those dependencies? Can you decouple them? – Mark Seemann Jun 29 '21 at 13:32
  • @MarkSeemann, want/need, yes. AS an example: ILogger is "needed" for Exceptions. ILogger differs between class instances. I can only pass around ILogger. A couple of my classes needs to pass to multiple instances 3 DI instances (repository, mapper, logger). Seems silly to have a need to know every possibility of "Child" classes especially when using "SOLID" design – Kelly Harris Jun 29 '21 at 13:42
  • 1
    @KellyHarris I'd strongly recommend that you rethink that design. [Logging should not be a dependency](https://stackoverflow.com/a/7906547/126014). – Mark Seemann Jun 29 '21 at 14:00
  • @MarkSeemann, how should I log errors and the related information? If you have a better design, please provide. Thanks – Kelly Harris Jun 29 '21 at 14:23
  • 1
    @KellyHarris when you have more than ~5 injections you probably have a software design issue. You should consider splitting your classes und smaller once. If the problem is only your logging instances I think MarkSeemann has provided a good link for that. – René Jun 29 '21 at 15:42
  • 1
    @KellyHarris I already pointed you to resources that answer those questions. I can't provide a better design for the OP code, since it's not clear that that code produces any errors, nor has other logging needs. – Mark Seemann Jun 29 '21 at 15:50
  • Thank You @MarkSeemann for your help. I find it interesting how most every example with DI uses logging as a service yet you say it is not. – Kelly Harris Jun 30 '21 at 11:39