Dot-Net

Simple Injector 是否可以通過對象工廠註冊條件?

  • January 18, 2017

我看到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")

從範例原始碼中,如何註冊它們以 在創建時將對像傳遞給建構子,並在創建locatorForCSVFileScannerCSVFileScanner將對像傳遞給建構子?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);

引用自:https://stackoverflow.com/questions/34087864