Yükleniyor...

C# Dependency Injection Temelleri

C#’ta Dependency Injection kavramını öğrenin. Bağımlılıkların yönetimi, gevşek bağlılık ve test edilebilirlik örneklerle anlatılıyor.

Yazılım geliştirmede Dependency Injection (DI), bağımlılıkları yönetmek için kullanılan önemli bir tasarım desenidir. DI sayesinde sınıflar, ihtiyaç duydukları nesneleri kendi içlerinde oluşturmaktansa dışarıdan alır. Böylece kod daha esnek, test edilebilir ve sürdürülebilir hale gelir. C# ve .NET Core ekosisteminde DI, gömülü olarak desteklenmektedir.


Bağımlılık Nedir?

Bir sınıf, başka bir sınıfın işlevine ihtiyaç duyduğunda ona bağımlıdır. Örneğin, OrderService sipariş oluştururken bir ILogger nesnesine ihtiyaç duyabilir. Eğer OrderService doğrudan new Logger() kullanırsa, bu durumda Logger sınıfına sıkı sıkıya bağlı olur.


public class OrderService
{
    private readonly Logger _logger = new Logger();

    public void CreateOrder(string product)
    {
        _logger.Log($"Sipariş oluşturuldu: {product}");
    }
}

public class Logger
{
    public void Log(string message) => Console.WriteLine(message);
}

Bu yaklaşımda Logger değiştirilemez; farklı bir loglama sistemi kullanmak isterseniz OrderService kodunu değiştirmeniz gerekir. İşte Dependency Injection bu noktada devreye girer.


Dependency Injection ile Çözüm

DI kullanıldığında bağımlılıklar soyutlanır ve dışarıdan (constructor veya metot parametresi ile) sağlanır. Bu sayede OrderService, ILogger arayüzüne bağımlı olur; hangi loglayıcının kullanılacağına dış dünya karar verir.


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

public class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine("[Console] " + message);
}

public class FileLogger : ILogger
{
    public void Log(string message) => 
        System.IO.File.AppendAllText("log.txt", message + "\n");
}

public class OrderService
{
    private readonly ILogger _logger;

    // Constructor Injection
    public OrderService(ILogger logger)
    {
        _logger = logger;
    }

    public void CreateOrder(string product)
    {
        _logger.Log($"Sipariş oluşturuldu: {product}");
    }
}

class Program
{
    static void Main()
    {
        // Farklı logger seçilebilir
        ILogger logger = new ConsoleLogger();
        var service = new OrderService(logger);

        service.CreateOrder("Laptop");
    }
}

Bu örnekte OrderService artık belirli bir Logger sınıfına bağlı değildir, sadece ILogger arayüzüne bağımlıdır. Böylece ConsoleLogger veya FileLogger kolayca kullanılabilir.


Dependency Injection Türleri


.NET Core’da DI Kullanımı

.NET Core uygulamalarında DI container yerleşik olarak bulunur. Program.cs veya Startup.cs dosyasında servisler kaydedilir ve ihtiyaç duyulan sınıflara otomatik olarak enjekte edilir.


var builder = WebApplication.CreateBuilder(args);

// Servisleri kaydet
builder.Services.AddScoped<ILogger, ConsoleLogger>();
builder.Services.AddScoped<OrderService>();

var app = builder.Build();

app.MapGet("/order", (OrderService service) =>
{
    service.CreateOrder("Telefon");
    return "Sipariş işlendi.";
});

app.Run();

Burada DI container, OrderService için otomatik olarak bir ConsoleLogger nesnesi oluşturur ve enjekte eder.


Avantajları


TL;DR

  • Dependency Injection: Sınıfların ihtiyaç duyduğu nesneleri dışarıdan almasıdır.
  • Constructor Injection: En yaygın yöntemdir, bağımlılıklar yapıcı metotla alınır.
  • .NET Core: Yerleşik DI container sağlar.
  • Faydaları: Daha esnek, test edilebilir ve bakımı kolay bir mimari sunar.

İlişkili Makaleler

C# ile SOLID Prensipleri

C# örnekleriyle SOLID prensiplerinin uygulanışı: daha esnek, sürdürülebilir ve test edilebilir kod tasarımları.