Dependency Inversion Principle with .NET Framework Classes

I am trying to understand the principles of SOLID, in particular the Dependency Inversion Principle .

In this SO answer , this is explained very well.

I think I realized that I cannot create any instance of the class inside my class. Correctly?

But if I need to save some content to disk, can I create an instance of System.IO.File or do I need to enter it

I don’t understand where the limit is, if I cannot use my own classes or cannot none of the .NET Framework classes (or something else).

UPDATE :
I think File is a bad example because it is declared as static.

By the way, is this principle applicable to static classes ?

+8
c # solid-principles software-design
source share
3 answers

S SOLID stands for SRP (Single Responsibility Principle). You will not violate it using System.IO.File inside the class directly, once you save this class with one responsibility.

This is a good idea trying to distract the purpose of using System.IO.File . Suppose you need this to create a log. Then you will probably do something like:

 public interface IMyLogger { void GenerateLog(IEnumerable<string> content); } public class FileLogger: IMyLogger { public void GenerateLog(IEnumerable<string> content) { System.IO.File.WriteAllLines("C:/Log", content); } } 

Perhaps this is not just a journal, it is something more important, for example, creating a file, so that another system / application (even an external one) reads it and does some work.

If you are trying to use the DDD approach, the interface may belong to your domain, and the implementation may belong to the application. Then you register your interface as a service and enter it.

For a class that needs IMyLogger , it does not need to know how the log is created, it just needs to complete the task.

You can apply the same idea when you need to send an email inside any business logic in your domain. Instead of connecting directly to Exchange inside your domain, create an INotifier and MailNotifier that implements it for input.

+3
source share

Somewhere in the dependency chain you will need to use a specific class directly. Even if you use a DI infrastructure such as Ninject, the structure itself will create an instance of a specific type, so it will not be introduced into the structure (which, of course, does not make sense).

You can only distract something to a certain level. It will vary from project to project - you should ask yourself if you need a different level of abstraction (be it modularity, unit testing, etc.). I think this is very important - you want to be pragmatic, and not create layers on layers of abstractions just for the sake of it.

By the way, is this principle applicable to static classes?

Yes Yes. But with static classes, you must introduce a wrapper that will delegate calls to a static class, because a static class cannot implement interfaces.

+2
source share

It makes no sense to apply the principle only for its sake. Think pragmatically.

If you want to test a method that uses hard-coded file accesses, your unit tests will access these files. This is usually undesirable since you must configure or clean these files. To avoid this, you must introduce a service that wraps these file calls. This allows you to replace the real service with a fake one during unit tests. This fake service can provide hard-coded test data for read access and upload recorded data to memory for later analysis or just do nothing. Btw: NSubstitute can easily create fake services at runtime.

Enabling services allows you to achieve Unit Test isolation. For example. you can test some logic, regardless of the correct processing of files or access to databases or the proper functioning of other services. Injecting a service is just one way to do this. You can also simply specify the method parameter as an IEnumerable<string> with the contents of the file. Events can also be used for decoupling. Instead of writing to the log, you can create a log event.


In most DI infrastructures, you can specify the lifetime of objects. One of these parameters is Singleton , which means that the DI container will always return the same instance of the requested service. This allows you to transfer static classes to a service that behaves statically.

+1
source share

All Articles