C# 使用注册上下文注册的功能在哪里(又称Func<;T>;)?
我可以使用instanceCreator上下文(akaC# 使用注册上下文注册的功能在哪里(又称Func<;T>;)?,c#,.net,dependency-injection,ioc-container,simple-injector,C#,.net,Dependency Injection,Ioc Container,Simple Injector,我可以使用instanceCreator上下文(akaFunc)注册一个注册项,但是对于RegisterAll似乎没有相同的容差 TL;DR-找到接受的答案并查看更新2(或跳到更新3) 这就是我想做的: container.RegisterAll<IFileWatcher>( new List<Func<IFileWatcher>> { () => new FileWatcher( @".\Trig
Func
)注册一个注册项,但是对于RegisterAll似乎没有相同的容差
TL;DR-找到接受的答案并查看更新2(或跳到更新3)
这就是我想做的:
container.RegisterAll<IFileWatcher>(
new List<Func<IFileWatcher>>
{
() => new FileWatcher(
@".\Triggers\TriggerWatch\SomeTrigger.txt",
container.GetInstance<IFileSystem>()),
() => new FileWatcher(
@".\Triggers\TriggerWatch\SomeOtherTrigger.txt",
container.GetInstance<IFileSystem>())
});
您可以看到,我正在获取以前注册的文件监视程序的所有实例
我需要知道的是这个问题的一个简单解决方法,以及何时实施(或者如果不实施,为什么不实施)。我也同意,鉴于目前简单喷油器设计的局限性,这是不可能的。我不会接受的是,我需要更改和调整我的体系结构以满足工具的限制。
更新2
让我们来谈谈OCP(开闭原理,也称为实线中的O),以及SimpleInjector在某些情况下是如何打破这一特殊原理的
开闭原理就是,开是为了扩展,闭是为了修改。这意味着您可以更改实体的行为,而无需更改其源代码
现在让我们转到一个与此相关的示例:
var tasks = container.GetAllInstances<ITask>();
foreach (var task in tasks.OrEmptyListIfNull())
{
//registers the task with the scheduler, Rx Event Messaging, or another trigger of some sort
task.Initialize();
}
var tasks=container.GetAllInstances();
foreach(tasks.OrEmptyListIfNull()中的var task)
{
//向调度程序、Rx事件消息或其他某种触发器注册任务
task.Initialize();
}
注意这是多么干净。但要做到这一点,我需要能够注册接口的所有实例:
container.RegisterAll<ITask>(
new List<Func<ITask>>{
() => new FileWatchTask(container.GetInstance<IFileSystem>(),container.GetInstance<IMessageSubscriptionManagerService>(),configuration,container.GetAllInstances<IFileWatcher>()),
() => new DefaultFtpTask(container.GetInstance<IFtpClient>(),container.GetInstance<IFileSystem>()),
() => new DefaultImportFilesTask(container.GetInstance<IFileSystem>())
}
);
container.RegisterAll(
新名单{
()=>新的FileWatchTask(container.GetInstance(),container.GetInstance(),配置,container.GetAllInstances()),
()=>新的DefaultFtpTask(container.GetInstance(),container.GetInstance()),
()=>新的DefaultImportFilesTask(container.GetInstance())
}
);
对吧??所以这里的教训是,这很好,符合OCP。我可以通过添加或删除已注册的项来更改任务运行程序的行为。打开以进行扩展,关闭以进行修改
现在,让我们集中精力尝试下面答案中建议的方法(在第二次更新之前,它最终回答了这个问题),作者给人的印象是这是一个更好的设计
让我们从维护人员提到的好的注册设计开始。我得到的观点是,我必须牺牲我的代码,以某种方式使ITask更灵活地使用SimpleInjector:
container.Register<ITask<SomeGeneric1>(() => new FileWatchTask(container.GetInstance<IFileSystem>(),container.GetInstance<IMessageSubscriptionManagerService>(),configuration,container.GetAllInstances<IFileWatcher>()));
container.Register<ITask<SomeGeneric2>(() => new DefaultFtpTask(container.GetInstance<IFtpClient>(),container.GetInstance<IFileSystem>()));
container.Register<ITask<SomeGeneric3>(() => new DefaultImportFilesTask(container.GetInstance<IFileSystem>()));
container.Register新建FileWatchTask(container.GetInstance(),container.GetInstance(),configuration,container.GetAllInstances());
注册新的DefaultFtpTask(container.GetInstance(),container.GetInstance());
注册新的DefaultImportFilesTask(container.GetInstance());
现在让我们看看这是如何改变我们的设计的:
var task1 = container.GetInstances<ITask<SomeGeneric1>();
task1.Initialize();
var task2 = container.GetInstances<ITask<SomeGeneric2>();
task2.Initialize();
var task3 = container.GetInstances<ITask<SomeGeneric3>();
task3.Initialize();
var task1=container.GetInstances从您的第一个示例(使用列表
)中,我了解到您想要注册一个临时FileWatcher集合。换句话说,每次迭代列表时,都应该创建一个新的文件查看器实例。当然,这与向两个(单例)FileWatcher(总是返回相同的实例)注册列表非常不同。然而,在您的问题中有一些含糊不清的地方,因为在扩展方法中,您似乎将它们注册为singleton。在我接下来的回答中,我假设你想要短暂的行为
创建RegisterAll
的常见用例是为公共接口注册实现列表。例如,一个应用程序具有多个IEventHandler
实现,当引发CustomerMoved
事件时,所有这些实现都需要触发。在这种情况下,您为registeral
方法提供了System.Type
实例列表,容器完全可以为您控制这些实现的连接。由于容器控制创建,因此集合称为“容器控制”
然而,RegisterAll
只是将创建转发回容器,这意味着默认情况下,列表会创建临时实例(因为未注册的具体类型被解析为临时)。这似乎有些尴尬,但它允许您注册一个包含不同生活方式元素的列表,因为您可以使用所选的生活方式显式注册每个项目。它还允许您向registeral
提供抽象(例如typeof(iSeries设备)
),这也可以工作,因为请求被转发回容器
然而,您的用例是不同的。您希望注册一个完全相同类型的元素列表,但每个元素都具有不同的配置值。为了让事情变得更困难,你似乎想把它们注册为瞬态而不是单态。通过不向RegisterAll
传递类型列表,而是向IEnumerable
容器传递类型,容器不会创建并自动连接这些类型,我们称之为“容器非受控”集合
长话短说:我们如何注册?有多种方法可以做到这一点,但我个人喜欢这种方法:
string[]触发器=new[]
{
@“\Triggers\TriggerWatch\SomeTrigger.txt”,
@“\Triggers\TriggerWatch\SomeOtherTrigger.txt”
};
集装箱登记处(
从触发器中的触发器
选择新的FileWatcher(触发器,
container.GetInstance())
);
这里我们使用RegisterAll
方法注册一个LINQ查询(它只是一个IEnumerable
)。每次有人解析一个IEnumerable
时,它都会返回同一个查询,但由于该查询的select包含一个newFileWatcher
,因此在迭代时总是返回新实例。T
container.Register<ITask<SomeGeneric1>(() => new FileWatchTask(container.GetInstance<IFileSystem>(),container.GetInstance<IMessageSubscriptionManagerService>(),configuration,container.GetAllInstances<IFileWatcher>()));
container.Register<ITask<SomeGeneric2>(() => new DefaultFtpTask(container.GetInstance<IFtpClient>(),container.GetInstance<IFileSystem>()));
container.Register<ITask<SomeGeneric3>(() => new DefaultImportFilesTask(container.GetInstance<IFileSystem>()));
var task1 = container.GetInstances<ITask<SomeGeneric1>();
task1.Initialize();
var task2 = container.GetInstances<ITask<SomeGeneric2>();
task2.Initialize();
var task3 = container.GetInstances<ITask<SomeGeneric3>();
task3.Initialize();
public class SomeClass {
public SomeClass(IEnumerable<ITask> tasks){}
}
public class SomeClass {
public SomeClass(ITask<Generic1> task1,
ITask<Generic2> task2,
ITask<Generic3> task3
) {}
}
var watchers = container.GetAllInstances<IFileWatcher>();
var first1 = watchers.First();
var first2 = watchers.First();
Assert.AreNotEqual(first1, first2, "Should be different instances");
Assert.AreEqual(first1.Trigger, first2.Trigger);
container.RegisterSingle<IEnumerable<IFileWatcher>>(() =>
{
return
from
var list = new List<IFileWatcher>
{
new FileWatcher(@".\Triggers\TriggerWatch\SomeTrigger.txt", container.GetInstance<IFileSystem>()),
new FileWatcher(@".\Triggers\TriggerWatch\SomeOtherTrigger.txt", container.GetInstance<IFileSystem>())
};
return list.AsReadOnly();
});
container.Register<ITask<SomeGeneric1>(() => new FileWatchTask(container.GetInstance<IFileSystem>(),container.GetInstance<IMessageSubscriptionManagerService>(),configuration,container.GetAllInstances<IFileWatcher>()));
container.Register<ITask<SomeGeneric2>(() => new DefaultFtpTask(container.GetInstance<IFtpClient>(),container.GetInstance<IFileSystem>()));
container.Register<ITask<SomeGeneric3>(() => new DefaultImportFilesTask(container.GetInstance<IFileSystem>()));
container.Register<ITask<SomeGeneric1>, FileWatchTask>();
container.Register<ITask<SomeGeneric2>, DefaultFtpTask>();
container.Register<ITask<SomeGeneric3>, DefaultImportFilesTask>();
// using SimpleInjector.Extensions;
container.RegisterManyForOpenGeneric(typeof(ITask<>), typeof(ITask<>).Assembly);
// using SimpleInjector.Extensions;
container.RegisterDecorator(typeof(ITask<>), typeof(TransactionTaskDecorator<>));
container.RegisterDecorator(typeof(ITask<>), typeof(TransactionTaskDecorator<>));
container.RegisterDecorator(typeof(ITask<>), typeof(DeadlockRetryTaskDecorator<>));
container.RegisterDecorator(typeof(ITask<>), typeof(ValidationTaskDecorator<>),
context => ShouldApplyValidator(context.ServiceType));
var taskTypes = (
from type in typeof(ITask).Assemby.GetTypes()
where typeof(ITask).IsAssignableFrom(type)
where !type.IsAbstract && !type.IsGenericTypeDefinition
select type)
.ToList();
// Register all as task types singleton
taskTypes.ForEach(type => container.Register(type, type, Lifestyle.Singleton));
// registers a list of all those (singleton) tasks.
container.RegisterAll<ITask>(taskTypes);
var taskTypes =
from type in typeof(ITask).Assemby.GetTypes()
where typeof(ITask).IsAssignableFrom(type)
where !type.IsAbstract && !type.IsGenericTypeDefinition
select type;
// registers a list of all those (singleton) tasks.
container.RegisterAll(typeof(ITask),
from type in taskTypes
select Lifestyle.Singleton.CreateRegistration(type, type, container));