Three main styles of dependency injection

From Logic Wiki
Jump to: navigation, search


Constructor Injection (most common & recommended)

Idea :

Dependencies are provided through the constructor. If the object exists, its dependencies must exist too.

Example

public interface ILogger
{
    void Log(string message);
}

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

public class OrderService
{
    private readonly ILogger _logger;

    public OrderService(ILogger logger) // injected here
    {
        _logger = logger;
    }

    public void PlaceOrder()
    {
        _logger.Log("Order placed");
    }
}
<pre>
=== Usage ===
<pre>
ILogger logger = new ConsoleLogger();
OrderService service = new OrderService(logger);
service.PlaceOrder();

Pros and Cons

✅ Pros

  • Dependencies are mandatory
  • Class is always in a valid state
  • Easy to test
  • Works perfectly with DI containers

❌ Cons

  • Constructor can get long if there are many dependencies

Setter Injection (Property Injection)

Idea :

Dependencies are assigned through public properties after the object is created.

Example

public class OrderService
{
    public ILogger Logger { get; set; }  // injected via property

    public void PlaceOrder()
    {
        Logger?.Log("Order placed");
    }
}

Usage

OrderService service = new OrderService();
service.Logger = new ConsoleLogger();
service.PlaceOrder();

Pros and Cons

✅ Pros

  • Useful for optional dependencies
  • Flexible
  • Cleaner constructor

❌ Cons

  • Object can exist in an invalid state
  • Dependency might be forgotten
  • Harder to enforce correctness

Interface Injection (rarely used)

Idea :

The dependency provides itself via a special interface method.

Example

public interface ILogger
{
    void Log(string message);
}

public interface ILoggerAware
{
    void SetLogger(ILogger logger);
}

public class OrderService : ILoggerAware
{
    private ILogger _logger;

    public void SetLogger(ILogger logger)
    {
        _logger = logger;
    }

    public void PlaceOrder()
    {
        _logger.Log("Order placed");
    }
}

Usage

OrderService service = new OrderService();
service.SetLogger(new ConsoleLogger());
service.PlaceOrder();

Pros and Cons

✅ Pros

  • Explicit injection contract
  • Dependency clearly declared

❌ Cons

  • More boilerplate
  • Not supported by most DI containers
  • Rare in real-world C# apps