我看到Simple Injector的容器有method
public void RegisterConditional<TService, TImplementation>(
Predicate<PredicateContext> predicate
)
但是我想为不同的服务使用相同实现的不同对象,所以我需要的重载方法看起来像这样
public void RegisterConditional<TService>(
Func<TService> instanceCreator,
Predicate<PredicateContext> predicate
)
但SimpleInjector没有它。我正在尝试找到其他Container的方法来注册具有服务条件的实例创建者。 还有其他方法吗?
或者,我试图做的不是好的设计,所以开发人员没有实现它?
编辑:添加了示例和更详细的问题。
示例
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
后的{1}}构造函数?
答案 0 :(得分:11)
或者,我试图做的不是好的设计,所以开发人员没有实现它?
在看到你的例子之后,我必须得出结论,可能存在设计缺陷。设计的主要问题是您似乎违反了Liskov Substitution Principle(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没有它。我正在尝试找到其他Container的方法来注册具有服务条件的实例创建者。还有其他方法吗?
您实际上可以使用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);