Customize Consent Preferences

We use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.

The cookies that are categorized as "Necessary" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... 

Always Active

Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.

No cookies to display.

Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.

No cookies to display.

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.

No cookies to display.

Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.

No cookies to display.

Advertisement cookies are used to provide visitors with customized advertisements based on the pages you visited previously and to analyze the effectiveness of the ad campaigns.

No cookies to display.

blog
Ottorino Bruni  

Dependency Inversion Principle (DIP) in C#

In my previous articles I wrote about Solid Principles in C#.

In this article, I am going to show you when and how to use the Dependency Inversion Principle (DIP) in C# with an example project. You can find the repository on GitHub.

The master branch shows the initial code used in the example.  There are separate tags and branches for each of the all solid principles that you can review or download as well. Here are links you can use to jump to these tagged versions in your browser:

What is the Dependency Inversion Principle (DIP) in C#?

The Dependency Inversion Principle (DIP) is the last, in alphabetical order, of the SOLID design principles. We can always reuse the definition from Wikipedia.

High-level modules should not import anything from low-level modules. Both should depend on abstractions.

Abstractions should not depend on details. Details should depend on abstractions.

Let’s try to summarize these two definitions:

  • Instead of high-level modules relying directly on low-level modules, both should communicate through abstract interfaces. This promotes flexibility and allows for easier substitution of components.
  • Abstractions should not be tightly coupled to specific implementations; instead, the concrete details should adhere to the abstractions. This allows you to change or extend implementations without affecting the overall structure of your code.

Abstractions describe what:

  • Send a message;
  • Store a record;

Details specify how to do:

  • Send a push notification to a device;
  • Deserialize an object and store in a database;

In this example we expose implementation details and making the interface much less reusable. The interface should not know the details of the database, in this case mysql.

public interface IOrderDataAccess
{
    MySqlDataReader GetOrders(MySqlParameterCollection params);
}

This example hide the details above and make the interface reusable.

public interface IOrderDataAccess
{
    List<Order> GetOrders(Dictionary<string, string> params);
}

What are Abstractions in C#?

In C#, there are two types of abstractions:

  • C#  Interface, Interfaces define a contract that classes must adhere to by implementing their methods, properties, events, or indexers. You can have as many interfaces as needed in your code, and a single class can implement multiple interfaces. 
  • C# Abstract Class, Abstract classes provide a way to create a partial implementation of a class while leaving some methods or properties to be implemented by derived classes. You can have multiple abstract classes in your code, and a single class can inherit from one abstract class while implementing multiple interfaces.

Dependency Inversion Principle (DIP) and Dependency Injection (DI)  are they the same thing?

No, the Dependency Inversion Principle (DIP) is a higher-level design principle that emphasizes the use of abstractions and the reduction of direct dependencies between modules, while Dependency Injection (DI) is a practical technique used to implement DIP.

Dependency Injection (DI) allows you to achieve Dependency Inversion Principle (DIP) by injecting dependencies into classes or components from the outside.

Why should you use the Dependency Inversion Principle (DIP)?

  • Flexibility and Extensibility. It promotes loose coupling between modules or components by depending on abstractions rather than concrete implementations.
  • Testability. It makes it easier to write unit tests for your code. By depending on abstractions, you can easily create mock or stub implementations of dependencies for testing purposes.
  • Parallel Development. It enables parallel development by allowing teams or individuals to work on different parts of the system independently.
  • Improved Code Reusability. Abstractions created in accordance with Dependency Inversion Principle (DIP) can be reused across different parts of your application or even in entirely different projects.
  • Separation of Concerns. It encourages better separation of concerns in your code. High-level modules focus on defining what needs to be done (abstractions), while low-level modules handle how things are done (concrete implementations).

How can i use the Dependency Inversion Principle (DIP)?

These are the typical approaches to Dependency Inversion Principle (DIP):

  • Use Abstractions (Interfaces or Abstract Classes).
// Define an abstraction (interface) 
public interface IDataProvider { 
    string GetData(); 
}
  • Implement Concrete Classes That Adhere to Abstractions.
// Implement a concrete class that adheres to the abstraction
public class SqlDataProvider : IDataProvider
{
    public string GetData()
    {
        // Implement data retrieval from SQL
        return "Data from SQL";
    }
}
  • Apply Dependency Injection (DI).
public class DataProcessor
{
    private readonly IDataProvider dataProvider;

    // Use constructor injection to inject the dependency
    public DataProcessor(IDataProvider dataProvider)
    {
        this.dataProvider = dataProvider;
    }

    public string ProcessData()
    {
        // Use the injected dependency
        var data = dataProvider.GetData();
        // Process the data
        return "Processed: " + data;
    }
}
services.AddScoped<IDataProvider, SqlDataProvider>(); 
services.AddTransient<DataProcessor>();

How we can refactor the code applying the Dependency Inversion Principle (DIP)?

Please have a look at how I have refactored my previous code here DIP-END

If you think your friends/network would find this useful, please share it with them. I’d really appreciate it.

Thanks for reading! ????

 

 

🚀 Discover CodeSwissKnife, your all-in-one, offline toolkit for developers!

Click to explore CodeSwissKnife 👉

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.