[英]Ninject Factory: Create the appropriate class based on a parameter
我有3節課:
class SqlQueryService : IQueryService
class FileQueryService : IQueryService
class NCRFileQueryService : FileQueryService
我已經創建了一個接口工廠:
public interface IQueryServiceFactory
{
IQueryService Create(string connection);
}
在應用程序模塊中:
Bind(typeof(IQueryService)).To(typeof(SqlQueryService)).Named("Data Source");
Bind(typeof(IQueryService)).To(typeof(NCRFileQueryService)).Named("NCR File Source");
Bind(typeof(IQueryService)).To(typeof(FileQueryService)).Named("File Source");
Bind<IQueryServiceFactory>().ToFactory();
在我的應用中,我想基於如下參數創建三個類之一的實例:
IQueryService queryService =
_queryServiceFactory.Create(_configuration.SelectedTPV.Connection);
SqlQueryService
FileQueryService
NCRFileQueryService
有可能做到嗎?
*注意:我的應用程序是帶有.NET Framework 3.5的Winforms應用程序,因為它是用於OLD窗口的
我使用的Ninject版本是3.2.2.0,Ninject Extensions Factory的版本是3.2.1.0
您可以通過創建自定義實例提供程序,然后像下面這樣綁定工廠來做到這一點:
this.Bind<IQueryServiceFactory>()
.ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());
請參閱文檔中的將第一個工廠方法參數視為名稱說明符 。
由於您提供給工廠的值不是用戶提供的值,因此不需要將使用代碼復雜化為:
使用者不應該依賴IQueryServiceFactory
,而應該依賴IQueryService
。 如何為消費者提供正確的實現方式,取決於您應用程序的需求,但是有兩種選擇。
如果在啟動時知道配置值,則在配置DI容器之前,這僅意味着您只需要基於該值在容器中注冊一個實現。
例如:
Bind(typeof(IQueryService),
value == "Data Source" ? typeof(SqlQueryService) :
value == "NCR File Source ? typeof(NCRFileQueryService) :
value == "File Source" ? typeof(FileQueryService) :
throw new InvalidOperationException(value));
即使在啟動時配置值不是固定的或未知的情況下,仍然沒有理由使用工廠抽象並讓使用者依賴該配置值。 通過創建代理,可以將其全部隱藏在IQueryService
抽象的后面:
public class ConfigurationSelectorQueryServiceProxy : IQueryService
{
private readonly IQueryService a;
private readonly IQueryService b;
private readonly IQueryService c;
public ConfigurationSelectorQueryServiceProxy(
SqlQueryService a, NCRFileQueryService b, FileQueryService c) {
this.a = a;
this.b = b;
this.c = c;
}
// IQueryService methods. Forward the call to one of the wrapped services
public object SomeMethod(object args) => GetService().SomeMethod(args);
// Helper methods
private IQueryService GetService() =>
// Read configuration value
GetService(_configuration.SelectedTPV.Connection);
private IQueryService GetService(string value) =>
value == "Data Source" ? (this.a :
value == "NCR File Source ? this.b :
value == "File Source" ? this.c :
throw new InvalidOperationException(value);
}
此ConfigurationSelectorQueryServiceProxy
代理實現可以注冊為IQueryService
並注入到使用者中。 這樣,消費者不必知道選擇正確實現的復雜性。 他們可以簡單地使用IQueryService
抽象。
謝謝歐文!
我讀了維基,但沒有意識到這種定制。
最后,我決定添加一個類似的類:
public class QueryServiceInstanceProvider : StandardInstanceProvider
{
protected override string GetName(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
string connection = arguments[0].ToString();
return connection.Split('=')[0];
}
protected override Ninject.Parameters.IConstructorArgument[] GetConstructorArguments(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
}
}
並在應用程序模塊中:
Bind(typeof(IQueryService)).To(typeof(SqlQueryService)).Named("Data Source");
Bind(typeof(IQueryService)).To(typeof(NCRFileQueryService)).Named("NCR File Source");
Bind(typeof(IQueryService)).To(typeof(FileQueryService)).Named("File Source");
Bind<IQueryServiceFactory>().ToFactory(() => new QueryServiceInstanceProvider());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.