如何使用简单的注入器将类型与其接口注册为单例?

oguzh4n

我有如下模型:

public interface IUserLookupService {
    Guid[] GetDirectChilds(Guid userId);
    Guid[] GetAllChilds(Guid userId);
    Guid GetDepartment(Guid userId);
}

public interface ICanRefreshCache{
    void Refresh();
}

public class XHandler : IEventHandler<UserNameChanged> { ... }
public class YHandler : IEventHandler<TeamCreated> { ... }

public class CachedUserLookupService
    : IUserLookupService,
    ICanRefreshCache,
    IEventHandler<UserNameChanged>
{
    private Func<ISession> _sessionFactory;
    private IDictionary<Guid, UserInfo> _users = new Dictionary<Guid, UserInfo>();

    public CachedUserLookupService(Func<ISession> sessionFactory) {
        _sessionFactory = sessionFactory;
    }

    public void Handle(UserNameChanged ev) {
        // change cache with new event parameters
    }

    public void Refresh() {
        var session = _sessionFactory();
        // get user from db then create userinfo...
    }

    public Guid[] GetDirectChilds(Guid userId) {
        // code
    }

    public Guid[] GetAllChilds(Guid userId) {
           // code
    }

    public Guid GetDepartment(Guid userId) {
        // code
    }

    public class UserInfo
    {
        public Guid Id { get; set; }
        public string FullName { get; set; }
        public Guid? ParentId {get;set;}
    }
}

public class CachedTeamService
    : ITeamService,
    ICanRefreshCache,
    IEventHandler<TeamCreated>{
    // similar with CachedUserLookupService
}

我的注册:

container.RegisterManyForOpenGeneric(typeof(IEventHandler<>),
    (closedServiceType, implementations) =>
    {
        container.RegisterAll(closedServiceType, implementations);
    },
    applicationAssembly, typeof(Constants).Assembly);

var serviceRegistrations = 
    from type in applicationAssembly.GetExportedTypes()
    where type.Name.EndsWith("Service")
    where !type.IsAbstract
    where !type.IsInterface
    select new
    {
        Services = type.GetInterfaces(),
        Implementation = type
    };

var lifeStyles = new Dictionary<Type, Lifestyle>()
{
    {typeof(CachedUserLookupService),Lifestyle.Singleton},
    {typeof(CachedTeamService),Lifestyle.Singleton}
};

List<Type> cacheableComponents = new List<Type>();
foreach (var reg in serviceRegistrations)
{
    foreach (var service in reg.Services)
    {
        Lifestyle lifeStyle;
        if (lifeStyles.TryGetValue(reg.Implementation, out lifeStyle) == false)
        {
            lifeStyle = Lifestyle.Singleton;
        }

        if (typeof(ICanRefreshCache) == service)
        {
            cacheableComponents.Add(reg.Implementation);
            continue;
        }

        container.Register(service, reg.Implementation, lifeStyle);
    }
}

container.RegisterAll(typeof(ICanRefreshCache), cacheableComponents);

我想在系统启动时使用ICanRefreshCache-> Refresh方法刷新所有缓存,所以我调用:

步骤1:

container.GetAllInstances<ICanRefreshCache>().Each(c=>c.Refresh());

第2步:

在我调用IEventHandler<UserNameChanged>或任何其他接口键入属于CachedUserLookupService(或CachedTeamService)的任何时间之后,返回的实例与步骤1实例不同,因此此注册无济于事。

我需要简单注入器注册才能提供以下调用。

// must return Singleton CachedUserLookupService + other 
// IEventHandler<UserNameChanged> implementations
container.GetAllInstances<IEventHandler<UserNameChanged>>(); 

// must return Singleton CachedTeamService + other 
// IEventHandler<TeamCreated> implementations
container.GetAllInstances<IEventHandler<TeamCreated>>();  

// must return Singleton CachedUserLookupService
container.GetInstance<IUserLookupService>();

// must return Singleton CachedTeamService
container.GetInstance<ITeamService>();

// must return Singleton CachedUserLookupService + Singleton CachedTeamService
container.GetAllInstances<ICanRefreshCache>(); 
史蒂文

注意:此答案中的信息已过时。在Simple Injector v4中,情况发生了很大变化。

如果我理解正确,则您有一个实现多个接口的组件,并且您希望每个注册都映射到该组件的相同实例。所以,不管你是否解决了ITeamServiceICanRefreshCache或者IEventHandler<TeamCreated>,你想要得到的同一个实例CachedTeamService

在Simple Injector中执行此操作的一般方法是Registration手动创建一个实例,并为每个接口注册它,如下所示:

var registration = 
    Lifestyle.Singleton.CreateRegistration<CachedTeamService>(container);

container.AddRegistration(typeof(ITeamService), registration);
container.AddRegistration(typeof(ICanRefreshCache), registration);
container.AddRegistration(typeof(IEventHandler<TeamCreated>), registration);

在这里解释

但是,您的情况要复杂一些,因为您将批量注册RegisterManyForOpenGeneric与常规注册一起使用。因此,您应该IEventHandler<TeamCreated>以单例形式取消想要的批量注册,或者您需要完全替换注册

但是,在这种情况下无法替换注册,因为Simple Injector不允许您替换集合中的注册。因此,我们可以按以下方式禁止该类型的注册:

Type[] typesToRegisterManually = new[]
{
    typeof(CachedTeamService)
};

container.RegisterManyForOpenGeneric(typeof(IEventHandler<>),
    (service, impls) =>
    {
        container.RegisterAll(service, impls.Except(typesToRegisterManually));
    },
    assemblies);

var registration = 
    Lifestyle.Singleton.CreateRegistration<CachedTeamService>(container);

container.AddRegistration(typeof(ITeamService), registration);
container.AddRegistration(typeof(ICanRefreshCache), registration);

// Using SimpleInjector.Advanced
container.AppendToCollection(typeof(IEventHandler<TeamCreated>), registration);

但是,我的经验是,复杂的注册通常表明您的代码中违反了SOLID原则。很难对您的设计提供任何具体的反馈,但是我发现具有这些多个接口的类很可能具有多种职责,并且有多种更改理由(它们违反了SRP),从而导致您在添加新功能时进行更改(这是违反OCP的行为)。

相反,我可以提供一些建议:

  • 将泛型逻辑IEventHandler<T>移到其自己的类中。事件处理程序显然是另一种责任,接口名称已经在告诉您这一点。然后,此类可以依赖于从中提取逻辑的旧类,也可以将事件处理程序所依赖的逻辑提取到其自己的类中,并使“旧”类和事件处理程序都依赖于此新的共享类。
  • IUserLookupService接口可以自主安排似乎是一种变相的资源库,这基本上意味着你违反了SRP,OCP和ISP(说明这篇文章)。因此,如该文章所述,自定义查询应具有自己的抽象:IQueryHandler<TQuery, TResult>这样可以很容易地将横切关注点应用到它们上,使其成为SOLID,并使用进行注册非常简单container.RegisterManyForOpenGeneric

这给您留下的是在大多数情况下仅实现一种抽象的类,但类实现的情况除外ICanRefreshCache对于这种特殊情况,我建议进行复合 ICanRefreshCache实现以允许触发ICanRefreshCache应用程序中的所有操作但是IEnumerable<ICanRefreshCache>与其将a注入到该复合物中,不应该将该复合物作为您的“合成根”的一部分,并使其依赖于容器。这使您可以在运行时搜索完整的配置以查找所有ICanRefreshCache实现。

这样的组合可能看起来像这样:

public class CanRefreshCacheComposite : ICanRefreshCache
{
    private readonly Lazy<InstanceProducer[]> canRefreshProducers;

    public CanRefreshCacheComposite(Container container) {
        this.canRefreshProducers = 
            new Lazy<InstanceProducer[]>(() => GetProducers(container).ToArray());
    }

    public void Refresh() {
        foreach (var producer in this.canRefreshProducers.Value) {
            var refresher = (ICanRefreshCache)producer.GetInstance();
            refresher.Refresh();
        }
    }

    private IEnumerable<InstanceProducer> GetProducers(Container container) {
        return
            from producer in container.GetCurrentRegistrations()
            where typeof(ICanRefreshCache).IsAssignableFrom(
                producer.Registration.ImplementationType)
            select producer;
    }
}

您可以按以下方式注册:

container.RegisterSingle<ICanRefreshCache, CanRefreshCacheComposite>();

// To make sure all all ICanRefreshCache implementations that are part of
// a collection are known to the container, call Verify() when you're done
// registering.
container.Verify();

这样,您可以简单地ICanRefreshCache从代码内部进行依赖,在其Refresh调用方法,然后复合方法将完成其余工作。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在简单注入器中将两个接口注册为单例的类的行为是什么

来自分类Dev

在简单注入器中将两个接口注册为单例的类的行为是什么

来自分类Dev

如何将更复杂的控制器名称注册为单例/非单例?

来自分类Dev

如何将更复杂的控制器名称注册为单例/非单例?

来自分类Dev

如何注册为单例或瞬态所有类型与StructureMap实现一个接口

来自分类Dev

使用简单注入器,是否可以通过其实现类型获得单例?

来自分类Dev

如何使用std函数在Qt中为回调注册单例qml类型?

来自分类Dev

如何将单例模式与依赖注入结合使用?

来自分类Dev

在IOC中为多个接口注册同一单例

来自分类Dev

如何使用简单注入器注册Drum.UriMaker <>?

来自分类Dev

如何使用简单注入器注册Drum.UriMaker <>?

来自分类Dev

简单注入器使用元数据注册多种类型的相同接口

来自分类Dev

简单注入器:如何测试注册?

来自分类Dev

使用简单注入器注册NLog ILogger

来自分类Dev

通过使用简单注入器应用的装饰器来获取单个指定混凝土类型的特定接口

来自分类Dev

简单注入器:使用构造函数参数注册开放泛型类型

来自分类Dev

简单的注入器-ApplicationSignInManager已注册为瞬态,但实现了IDisposable

来自分类Dev

如何使用简单注入器注入CacheItemPolicy

来自分类Dev

具有通用接口和组成的简单注入器-不注册接口

来自分类Dev

如何使Unity为2个注册接口注入相同的实例

来自分类Dev

如何将CDI拦截器创建为单例?

来自分类Dev

如何在简单注入器中注册实例集合

来自分类Dev

使用简单的注入器自动注册通用存储库

来自分类Dev

Automapper使用简单注入器(Ioc)将依赖项注入到自定义类型转换器中

来自分类Dev

Autofac:如何使用相同的接口注册多个类型以与装饰器一起使用?

来自分类Dev

如何使用简单注入器将依赖关系注入WCF属性

来自分类Dev

Julia如何将值识别为单例类型?

来自分类Dev

Julia如何将值识别为单例类型?

来自分类Dev

如何在Android中使用Roboguice将Google番石榴事件总线作为全局单例注入?

Related 相关文章

  1. 1

    在简单注入器中将两个接口注册为单例的类的行为是什么

  2. 2

    在简单注入器中将两个接口注册为单例的类的行为是什么

  3. 3

    如何将更复杂的控制器名称注册为单例/非单例?

  4. 4

    如何将更复杂的控制器名称注册为单例/非单例?

  5. 5

    如何注册为单例或瞬态所有类型与StructureMap实现一个接口

  6. 6

    使用简单注入器,是否可以通过其实现类型获得单例?

  7. 7

    如何使用std函数在Qt中为回调注册单例qml类型?

  8. 8

    如何将单例模式与依赖注入结合使用?

  9. 9

    在IOC中为多个接口注册同一单例

  10. 10

    如何使用简单注入器注册Drum.UriMaker <>?

  11. 11

    如何使用简单注入器注册Drum.UriMaker <>?

  12. 12

    简单注入器使用元数据注册多种类型的相同接口

  13. 13

    简单注入器:如何测试注册?

  14. 14

    使用简单注入器注册NLog ILogger

  15. 15

    通过使用简单注入器应用的装饰器来获取单个指定混凝土类型的特定接口

  16. 16

    简单注入器:使用构造函数参数注册开放泛型类型

  17. 17

    简单的注入器-ApplicationSignInManager已注册为瞬态,但实现了IDisposable

  18. 18

    如何使用简单注入器注入CacheItemPolicy

  19. 19

    具有通用接口和组成的简单注入器-不注册接口

  20. 20

    如何使Unity为2个注册接口注入相同的实例

  21. 21

    如何将CDI拦截器创建为单例?

  22. 22

    如何在简单注入器中注册实例集合

  23. 23

    使用简单的注入器自动注册通用存储库

  24. 24

    Automapper使用简单注入器(Ioc)将依赖项注入到自定义类型转换器中

  25. 25

    Autofac:如何使用相同的接口注册多个类型以与装饰器一起使用?

  26. 26

    如何使用简单注入器将依赖关系注入WCF属性

  27. 27

    Julia如何将值识别为单例类型?

  28. 28

    Julia如何将值识别为单例类型?

  29. 29

    如何在Android中使用Roboguice将Google番石榴事件总线作为全局单例注入?

热门标签

归档