C# 使用注册上下文注册的功能在哪里(又称Func<;T>;)?

C# 使用注册上下文注册的功能在哪里(又称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

我可以使用instanceCreator上下文(aka
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));