Take advantage of the dependency injection principle to provide support for pluggable implementations in your application and build loosely coupled, testable components The Dependency Inversion Principle states that the high level modules in an application should not depend on the low level modules; both should rather depend on abstractions. Both inversion of control and dependency injection are ways that enable you to break the dependencies between the components in your application. The IOC design pattern states that objects should not create objects on which they depend to perform some activity. As an example, you would typically have a business layer and a core or framework layer in your application. The business layer code should invoke the framework layer code. Using the IOC principle, this can be inverted, i.e., the framework layer would call the business layer. The IOC containers helps you in automatic instantiation and life cycle management of the objects. Some examples of popular IOC containers include Castle Windsor and Structure Map. Dependency injection Dependency injection is a subset of the Inversion of Control (IoC) principle. The DI principle is a technique that is used to remove internal dependencies from the implementation by enabling these dependencies to be injected externally. It states that when an object is dependent on other objects, such objects should be created using a separate framework or component. The IOC containers take advantage of dependency injection to invert the flow of control and provide the necessary implementation or the dependent code. In essence, while IoC is the ability of varying the implementation of a contract, DI is the ability to provide the necessary implementation when asked for. In other words, Dependency Injection is a realization of the Inversion of Control (IoC) principle. Martin Fowler has a great article on IoC and DI. There are basically three types of dependency injection: constructor injection, setter injection, and interface injection. While constructor injection uses a constructor to inject the dependencies, setter injection take advantage of setter properties to inject the object dependencies. The following code snippet illustrates how constructor injection is used. public class BusinessLogic { public BusinessLogic(BusinessEntity entity) { this.BusinessEntity = entity; } } Note how the dependency is passed using the constructor of the BusinessLogic class. interface injection uses interfaces to inject the dependencies. Implementing interface injection In this section we would implement dependency injection using interfaces, i.e., using the interface injection technique. The following code snippet shows three classes: EntityBase, Employee, and Customer. EntityBase is the base of both the entity classes Employee and Customer. public abstract class EntityBase { public Int32 ID { get; private set; } } public class Employee : EntityBase { //TODO: Properties that correspond to the Employee entity } public class Customer : EntityBase { //TODO: Properties that correspond to the Customer entity } Now, refer to the following interfaces. The ICustomerRepository and IEmployeeRepository interfaces inherit the IRepository interface — IRepository is the base interface here and declares a few repository methods. public interface IRepository { IQueryable<EntityBase> GetAll(); void Add(EntityBase entity); void Delete(EntityBase entity); void Edit(EntityBase entity); void Save(); } public interface ICustomerRepository : IRepository { Customer GetSingle(int customerId); } public interface IEmployeeRepository : IRepository { Employee GetSingle(int employeeId); } Note that the GetSingle method is specific to the ICustomerRepository and IEmployeeRepository interfaces. Now that the interfaces are in place, let’s create the concrete classes to perform CRUD operations for both the Customer and Employee entities. The following code snippet shows how the EmployeeRepository and CustomerRepository classes look like. Note that both these classes implement the IEmployeeRepository and ICustomerRepository interfaces respectively. public class EmployeeRepository :IEmployeeRepository { public Employee GetSingle(int employeeId) { throw new System.NotImplementedException(); } public IQueryable<EntityBase> GetAll() { throw new System.NotImplementedException(); } public void Add(EntityBase entity) { //Some code } public void Delete(EntityBase entity) { //Some code } public void Edit(EntityBase entity) { //Some code } public void Save() { //Some code } } public class CustomerRepository : ICustomerRepository { public Customer GetSingle(int customerId) { throw new System.NotImplementedException(); } public IQueryable<EntityBase> GetAll() { throw new System.NotImplementedException(); } public void Add(EntityBase entity) { throw new System.NotImplementedException(); } public void Delete(EntityBase entity) { throw new System.NotImplementedException(); } public void Edit(EntityBase entity) { throw new System.NotImplementedException(); } public void Save() { throw new System.NotImplementedException(); } } The following class represents the BusinessLogic class. Note that this is generic in nature and you would need to extend this class if need be to provide some specific implementation. For the sake of this illustration, this class contains just one property named Repository of type IRepository. public class BusinessLogic { public IRepository Repository { get; set; } } And, you are done! The following code snippet illustrates how the Add method of the EmployeeRepository class can be invoked. Note how the repository instance is injected using interface injection technique. static void Main(string[] args) { Employee emp = new Employee(); IEmployeeRepository repository = new EmployeeRepository(); BusinessLogic blObject = new BusinessLogic(); blObject.Repository = repository; blObject.Repository.Add(emp); } Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos