Kurucu Enjeksiyonu ve Arayüzler
Bileşenleri birbirinden ayırmak ve birim testini mümkün kılmak için arayüz tabanlı tasarımla kurucu enjeksiyonu uygulayın.
Kurucu Enjeksiyonu ve Arayüzler, CoddyKit'te ücretsiz bir C# Academy dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, C# Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. C# Academy kursu toplamda 4 dersten oluşur.
Yapıcı Üzerinden Bağımlılık Eklemenin Temelleri
Yapıcı üzerinden bağımlılık ekleme, en yaygın DI kalıbıdır. Bir sınıf bağımlılıklarını yapıcı parametreleri olarak bildirir ve kapsayıcı bunları örnek oluşturulurken sağlar.
Bu yaklaşım bağımlılıkları açık, zorunlu ve görünür kılar.
Arayüzü Tanımlama
Sözleşmeyi tanımlayan bir arayüzle başlayın. Bu sayede bağımlı kodu değiştirmeden farklı uygulamalar (gerçek, taklit veya bellek içi) arasında geçiş yapabilirsiniz.
public interface IProductRepository
{
Task<Product?> GetByIdAsync(int id);
Task<IEnumerable<Product>> GetAllAsync();
Task AddAsync(Product product);
}Arayüzü Uygulama
Somut uygulama gerçek işi yürütür — veritabanı çağrıları, HTTP istekleri ve benzeri işlemler. Tüketici, hangi uygulamayı aldığını hiçbir zaman bilmek zorunda değildir.
public class SqlProductRepository : IProductRepository
{
private readonly AppDbContext _db;
public SqlProductRepository(AppDbContext db) => _db = db;
public async Task<Product?> GetByIdAsync(int id)
=> await _db.Products.FindAsync(id);
public async Task<IEnumerable<Product>> GetAllAsync()
=> await _db.Products.ToListAsync();
public async Task AddAsync(Product product)
{
_db.Products.Add(product);
await _db.SaveChangesAsync();
}
}Yapıcı Üzerinden Kullanma
Hizmet katmanı, IProductRepository türünü yapıcı parametresi olarak alır. SqlProductRepository hakkında hiçbir şey bilmez — yalnızca arayüz sözleşmesini bilir.
public class ProductService
{
private readonly IProductRepository _repo;
private readonly ILogger<ProductService> _logger;
public ProductService(
IProductRepository repo,
ILogger<ProductService> logger)
{
_repo = repo;
_logger = logger;
}
public async Task<Product?> GetProductAsync(int id)
{
_logger.LogInformation("Fetching product {Id}", id);
return await _repo.GetByIdAsync(id);
}
}Zinciri Kaydetme
Zincirdeki her hizmeti kaydedin. Kapsayıcı, bağımlılık grafiğinin tamamını otomatik olarak çözümler — ProductService → IProductRepository → AppDbContext.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlite("Data Source=app.db"));
builder.Services.AddScoped<IProductRepository, SqlProductRepository>();
builder.Services.AddScoped<ProductService>();Taklit Nesneyle Sınama
Bağımlılıklar arayüzler üzerinden eklendiği için birim sınamaları veritabanına dokunmadan bir taklit veya sahte uygulama gönderebilir. Bu, DI'ın en büyük faydalarından biridir.
// Using NSubstitute or Moq in a unit test
var mockRepo = Substitute.For<IProductRepository>();
mockRepo.GetByIdAsync(1).Returns(new Product { Id = 1, Name = "Widget" });
var logger = Substitute.For<ILogger<ProductService>>();
var svc = new ProductService(mockRepo, logger);
var result = await svc.GetProductAsync(1);
Assert.Equal("Widget", result?.Name);Birden Çok Yapıcı Parametresi
Bir sınıfın çok sayıda yapıcı parametresi olabilir. Her biri kaydedildiği sürece kapsayıcı hepsini çözümler. Yapıcıları odaklı tutun — çok fazla parametre, sınıfın çok fazla sorumluluğu olduğuna işaret eder.
public class OrderService
{
public OrderService(
IOrderRepository orders,
IProductRepository products,
IEmailSender email,
ILogger<OrderService> logger)
{
// all injected by DI container
}
}Hizmet Bulucu Karşıt Kalıbından Kaçınma
NOT: İş mantığı metotlarında IServiceProvider ekleyip GetService çağırmayın. Bu, bağımlılıkları gizler ve sınamayı zorlaştırır. Açıkça tanımlanmış ve sınanabilir kod için yapıcı üzerinden bağımlılık eklemeyi tercih edin.
// BAD
public void Process(IServiceProvider sp)
{
var repo = sp.GetService<IProductRepository>(); // hidden dep!
}
// GOOD
public class Processor
{
private readonly IProductRepository _repo;
public Processor(IProductRepository repo) => _repo = repo;
}Birincil Yapıcı Sözdizimi (C# 12)
C# 12, tüm sınıf türleri için birincil yapıcıları kullanıma sunar ve kısa DI kodu için parametreleri doğrudan sınıf bildiriminde tanımlamanıza olanak tanır.
// C# 12 primary constructor
public class ProductService(
IProductRepository repo,
ILogger<ProductService> logger)
{
public async Task<Product?> GetAsync(int id)
{
logger.LogInformation("Getting {Id}", id);
return await repo.GetByIdAsync(id);
}
}Uygulamaları Değiştirme
Arayüz tabanlı DI'ın önemli bir avantajı şudur: Tüketici kodunu değiştirmeden tek satırda bir uygulamayı değiştirebilirsiniz. Bu, veritabanlarını, e-posta sağlayıcılarını veya özellik bayraklarını değiştirirken kullanışlıdır.
// Switch from SQL to in-memory for integration tests
if (environment.IsEnvironment("Test"))
builder.Services.AddScoped<IProductRepository, InMemoryProductRepository>();
else
builder.Services.AddScoped<IProductRepository, SqlProductRepository>();Gerçek Dünya: DI ile Denetleyici
ASP.NET Core denetleyicileri yapıcı üzerinden bağımlılık eklemeyi yerleşik olarak kullanır. Çatı tüm parametreleri çözümler ve bunları denetleyiciye aktarır.
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
private readonly ProductService _svc;
public ProductsController(ProductService svc) => _svc = svc;
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var product = await _svc.GetProductAsync(id);
return product is null ? NotFound() : Ok(product);
}
}Hızlı Kontrol
DI kullanırken arayüzlere göre programlamanın temel faydası nedir?
Özet: Yapıcı Üzerinden Bağımlılık Ekleme ve Arayüzler
Temel çıkarımlar:
- Bağımlılıkları yapıcı parametreleri olarak bildirin — kapsayıcı bunları sağlar
- Hizmet sözleşmeleri için arayüzler tanımlayın; somut türü değil, arayüzü ekleyin
- Arayüzler, birim sınamalarında kolay taklit oluşturmayı ve uygulamaları değiştirmeyi sağlar
- C# 12 birincil yapıcıları, DI ağırlıklı sınıflar için tekrarlanan kodu azaltır
- Hizmet bulucu karşıt kalıbından kaçının — bağımlılıkları açıkça koruyun
Sıkça Sorulan Sorular
“Kurucu Enjeksiyonu ve Arayüzler” dersi ücretsiz mi?
Evet — “Kurucu Enjeksiyonu ve Arayüzler” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve C# Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. C# Academy kursu toplamda 4 dersten oluşur.
“Kurucu Enjeksiyonu ve Arayüzler” dersinde ne öğreneceğim?
Bileşenleri birbirinden ayırmak ve birim testini mümkün kılmak için arayüz tabanlı tasarımla kurucu enjeksiyonu uygulayın. C# Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
C# Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te C# Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“Kurucu Enjeksiyonu ve Arayüzler” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu C# Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her C# Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- DI Kapsayıcılarının Temelleri
- Hizmet Ömürleri: Geçici, Kapsamlı, Singleton
- Kurucu Enjeksiyonu ve Arayüzler
- Fabrika ve Seçenekler Desenleri