Simple Injector 是否可以通過對象工廠註冊條件?
我看到Simple Injector的 Container 有這個方法
public void RegisterConditional<TService, TImplementation>( Predicate<PredicateContext> predicate )但是我想為不同的服務使用相同實現的不同對象,所以我需要的重載方法看起來像這樣
public void RegisterConditional<TService>( Func<TService> instanceCreator, Predicate<PredicateContext> predicate )但是 SimpleInjector 沒有它。我正在嘗試找到其他容器的方法來為服務條件註冊實例創建者。我還有其他方法可以做嗎?
或者,是我試圖做的不是好的設計,所以開發人員沒有實現它?
編輯:添加範例和更詳細的問題。
例子
class CSVFileScanner { public CSVFileScanner(IFileLocator fileLocator) { } } class XMLFileScanner { public XMLFileScanner(IFileLocator fileLocator) { } } class DefaultLogFileLocator: ILogFileLocator { public DefaultLogFileLocator(string directoryPath, string searchPattern) { } } var locatorForCSVFileScanner = new DefaultLogFileLocator("C:\CSVLogDir", "*.csv") var locatorForXMLFileScanner = new DefaultLogFileLocator("C:\XMLLogDir", "*.xml")從範例原始碼中,如何註冊它們以 在創建時將對像傳遞給建構子,並在創建
locatorForCSVFileScanner時CSVFileScanner將對像傳遞給建構子?CSVFileScanner``locatorForXMLFileScanner``XMLFileScanner``XMLFileScanner
或者,是我試圖做的不是好的設計,所以開發人員沒有實現它?
在看到您的範例後,我不得不得出結論,可能存在設計缺陷。設計的主要問題是您似乎違反了Liskov 替換原則(LSP)。LSP 是 SOLID 原則之一,它指出子類(或介面的實現)應該可以相互互換,而不會影響消費者。但是,在您的應用程序中,
XMLFileScanner當它提供 CSV 文件時,它似乎會中斷。所以從 LSP 的角度來看,這意味著兩個文件掃描器實現都應該有自己的抽象。一旦你給他們自己的抽象,問題就會完全消失。
但是,如果交換文件定位器對文件掃描器的工作沒有影響(例如,因為它們不讀取,而只是寫入),則不會違反 LSP 並且設計是可以的。
如果更改抽像不可行或不違反 LSP,則可以選擇使用工廠委託註冊文件掃描器,或者只需將其作為單例創建一次。這使您可以完全控制對像圖的該部分的組成。例如:
container.RegisterSingleton<CSVFileScanner>( new CSVFileScanner(new DefaultLogFileLocator("C:\CSVLogDir", "*.csv"))); container.RegisterSingleton<XMLFileScanner>( new XMLFileScanner(new DefaultLogFileLocator("C:\XMLLogDir", "*.xml")));但是 SimpleInjector 沒有它。我正在嘗試找到其他容器的方法來為服務條件註冊實例創建者。我還有其他方法可以做嗎?
您實際上可以使用
RegisterConditional方法來實現這一點,但是這個功能有點隱藏,這是故意的。Simple Injector 試圖促進建構在啟動階段完全已知的對像圖,並不鼓勵基於執行時條件建構對像圖。委託的使用Func<TService> instanceCreator允許制定執行時條件,這就是缺少這種重載的原因。但是,執行此操作的方法如下:
var csv = Lifestyle.Singleton.CreateRegistration<IFileLocator>( () => new DefaultLogFileLocator("C:\\CSVLogDir", "*.csv"), container); var xml = Lifestyle.Singleton.CreateRegistration<IFileLocator>( () => new DefaultLogFileLocator("C:\\XMLLogDir", "*.csv"), container); container.RegisterConditional(typeof(IFileLocator), csv, WhenInjectedInto<CSVFileScanner>); container.RegisterConditional(typeof(IFileLocator), xml, WhenInjectedInto<XMLFileScanner>); // Helper method. static bool WhenInjectedInto<T>(PredicateContext c) => c.Consumer.ImplementationType == typeof(T);