Dependency Injection In C#

Dependency injection is a design pattern that allows a class to receive its dependencies from external sources instead of creating them itself. This is often used to improve testability and flexibility of a class by allowing the dependencies to be easily swapped out for different implementations.

Here is an example of how dependency injection can be used in C#,

using System;
namespace DependencyInjectionExample {
    // An interface for a logger
    public interface ILogger {
        void Log(string message);
    }
    // A simple implementation of ILogger that writes messages to the console
    public class ConsoleLogger: ILogger {
        public void Log(string message) {
            Console.WriteLine(message);
        }
    }
    // A class that has a dependency on ILogger
    public class MyClass {
        private readonly ILogger logger;
        // Inject the logger dependency via the constructor
        public MyClass(ILogger logger) {
            this.logger = logger;
        }
        public void DoSomething() {
            // Use the injected logger to log a message
            this.logger.Log("Doing something");
        }
    }
    class Program {
        static void Main(string[] args) {
            // Create an instance of MyClass using the ConsoleLogger
            MyClass myClass = new MyClass(new ConsoleLogger());
            // Use the instance of MyClass
            myClass.DoSomething();
            // Wait for the user to press a key before exiting
            Console.ReadKey();
        }
    }
}

In the above example, the MyClass class has a dependency on the ILogger interface. Instead of creating an instance of ConsoleLogger itself, it receives the ConsoleLogger instance as an argument to its constructor and stores it in a private field. This allows the ConsoleLogger to be easily swapped out for a different implementation of ILogger if needed.

Final Thoughts

Using dependency injection in this way has several benefits. It makes the code more modular and easier to test, because the dependencies of an object can be easily replaced with mock or stub implementations for testing purposes. It also makes the code more maintainable, because the dependencies of an object can be easily updated without having to change the object itself. And it makes the code more flexible, because the dependencies of an object can be easily changed at runtime by modifying the registrations in the dependency injection container.