5

Kurucusunda dize vb. Gibi bazı ilkel tür argümanlara sahip bir sınıfım var.İlkel argüman yapıcı ile bir tür kayıt olun.

Türü birleşik kapsayıcıyla nasıl kaydettirmeliyim?

public LoginManager(
    IRegionManager regionManager, 
    IEventAggregator eventAggregator, 
    string mainRegionName, 
    Uri login, 
    Uri target) 
    { 
    this.regionManager = regionManager; 
    this.eventAggregator = eventAggregator; 
    this.mainRegionName = mainRegionName; 
    this.login = login; 
    this.target = target; 
    } 
} 

Güncelleme: IRegionManager ve IEventAggregator benim durumumda konteyner sarıcı Prism UnityBootstrapper için türleri bilinmektedir olduğunu
Anımsamak. Onları yeniden kaydetmem gerekiyor mu? Tip kayıt işlemini mümkün olduğunca basit tutmak istiyorum.

Bu kötü bir alışkanlık sayılır mı? Daha iyi alternatifler var mı?

cevap

12

dürüst olmak gerekirse, yapıcı içinde türlerini çözmek için ilkel veya sabit olan bir sınıf tasarıma sahip olması önlemek için çalışacağını söyledi. Zaten Tavares' cevabını gördüğümüz gibi, yapılandırma çok kırılgan olur konum (güncelleme: Tavares bana net olmaması nedeniyle onun cevabını kaldırdık görünüyor). Derleme zamanı desteğini kaybedersiniz ve bu yapıcıya yapılan her değişiklik DI yapılandırmanızı değiştirmenizi sağlar.

Bunu önlemek için tasarımı değiştirmek için birden fazla yolu vardır. Hangisi size uygun olduğunu size kalmış, ama burada birkaç fikir:

Seçenek 1: değişmez bir yapılandırma DTO kullanın:

private sealed class LoginManagerConfiguration 
{ 
    public Uri Login { get; private set; } 
    public Uri Target { get; private set; } 
    public string MainRegionName { get; private set; } 

    public LoginManagerConfiguration(Uri login, Uri target, string mainRegionName) 
    { 
     this.Login = login; 
     this.Target = target; 
     this.MainRegionName = mainRegionName; 
    } 
} 

Şimdi izin edebilirsiniz LoginManager bir bağımlılık almak LoginManagerConfiguration:

public LoginManager(IRegionManager regionManager, 
    IEventAggregator eventAggregator, 
    LoginManagerConfiguration configuration) 
{ 
    ... 
} 

LoginManagerConfiguration basitçe böyle kaydedilebilir:

0 yerine bu tip spesifik DTO Uygulama çaplı yapılandırma nesne belirtmek için cazip olabilir, ama bu bir tuzak. Bu tür uygulama çapında yapılandırma nesnesi, Service Locator anti-pattern'in yapılandırma eşdeğeridir. Bir türün hangi konfigürasyon değerlerini gerektirdiği belirsizleşir ve sınıfları test etmek zorlaşır.

Seçenek 2: Sadece DI konfigürasyonu amacıyla, bu sınıfın

Diğer bir seçenek bu sınıftan türetmek olduğunu türevi. Bu sınıf imzasını değiştiremezsiniz zaman özellikle yararlıdır (yani bir üçüncü taraf bileşen olduğunda):

private sealed class DILoginManager : LoginManager 
{ 
    DILoginManager(IRegionManager regionManager, 
     IEventAggregator eventAggregator) 
     : base(regionManager, eventAggregator, 
      ConfigurationManager.AppSettings["MainRegion"], 
      new Uri("Login"), 
      new Uri("Target")) 
    { 
     ... 
    } 
} 

başvurunuzun kompozisyon köküne yakın bu sınıfı tanımlayın.Bu sınıf, DI yapılandırmanızın bir uygulama ayrıntısı haline gelir. türünüze tescili artık çok basit olacaktır:

container.RegisterType<ILoginManager, DILoginManager>(); 

çağrıları ile Ama çok dikkatli olun böyle ConfigurationManager.AppSettings["MainRegion"] tembel yük yapılandırma değerleri,. Bu, yapılandırma hatalarının uygulama başlangıcı sırasında yakalanmadığı durumlara kolayca yol açabilir, ki bu gerçekten tercih edilir.

Seçenek 3: kullanın fabrika temsilci

ben sunmak istiyorum son seçenek bir fabrikasıdır. Bu Traveses'in cevabı gibi görünecek, fakat daha güvenlidir:

var mainRegion = ConfigurationManager.AppSettings["MainRegion"]; 

container.Register<ILoginManager>(new InjectionFactory(c => 
{ 
    return new LoginManager(
     c.Resolve<IRegionManager>(), 
     c.Resolve<IEventAggregator>(), 
     ConfigurationManager.AppSettings["MainRegion"], 
     new Uri("Login"), 
     new Uri("Target")); 
})); 

Umarım bu yardımcı olur.

+0

InjectionFactory yaklaşımı için, Func türlerini, bu parametreleri kabul eden ve bu şekilde bir ILoginManager döndüren bir InjectionFactory ile ilişkilendirmeniz için yazabilirsiniz: yeni InjectionFactory (c => (login, target) , mainRegionName) => c. öğesini (yeni ParameterOverride ("mainRegionName", mainRegionName), yeni ParameterOverride ("login", login), yeni ParameterOverride ("target", target)))) çözümleyin. Çözümü bu şekilde yaparak, bağımlılarınız için kurucunuzda esnek kalırsınız ve sadece ilkel parametre değişiklikleri için değiştirmek zorunda kalırsınız. –

+1

Çok güzel cevap, btw. –

+0

Eklemek için şunu ekleyin: kullanım bağımlılık olarak bir Func kabul edersiniz ve bu parametreleri ILoginManager verecek olan işleve iletirsiniz. Eğer bu ayarlarsa, Steven'ın yaklaşımına sadık kalacağım, ama eğer belirli bağlamlarda değişebilen çalışma zamanı değerleriyse, böyle bir şey yapmanız gerekebilir. –

0

Hayır, kötü bir alışkanlık değil. Bu mükemmel bir senaryo. Ben Unity dan ama açıkça istediğiniz yapıcı işaret ve tüm parametreleri numaralandırma vardır onunla kafamın üstünden ve ilkel olanlar new ResolvedParameter("your value") yapmak için geçti beri birkaç yıl geçti.

Ayrıca, orada bir Type parametresi olduğunu farkettim. Birlik ile temkinli olun, çünkü bunlarla baş etmenin çok şaşırtıcı bir yolu var. here'u detaylandıran bir blog yazım var.

+0

dziękuję. Lütfen güncellenmiş soruma bir göz atın. Benim özel durumumun bir örneğini sunabilirseniz sevinirim. BTW, nerede * başımın üstü *? Sanırım buna yığın mı deniyor? – Shimmy

+0

ResolvedParameter'ı, büyük miktarlarda ilkel maddeler için açıkça kullanmanıza gerek yoktur. –