Simple Injector - 具有瞬态依赖设计的单例

Simple Injector - Singleton with transient dependency design

背景

我知道 SimpleInjector 的 LifestyleMismatch 异常的用途以及它抛出它的原因。但假设有:

Players.dll

public abstract class PlayerEqualizer { ... }

public abstract class Player : IPlayer, ISongAware
{
    public Player(PlayerEqualizer eq)
    {
        Equalizer = eq;
    }

    public PlayerEqualizer Equalizer { get; }
    public abstract void StartPlay();
}

Players.Rock.dll

public class RockPlayerEqualizer  : PlayerEqualizer {}

public class RockPlayer : Player
{
    public RockPlayer(RockPlayerEqualizer  eq) : base(eq) {}

    public override void StartPlay() { ... }
}

public class RnBPlayer : Player
{
    public RnBPlayer(RockPlayerEqualizer  eq) : base(eq) {}

    public override void StartPlay() { ... }
}

Players.Pop.dll

public class PopPlayerEqualizer : PlayerEqualizer{}

public class PopPlayer : Player
{
    public PopPlayer(PopPlayerEqualizer eq) : base(eq) {}

    public override void StartPlay() { ... }
}

Player的所有实现都注册为IPlayer的集合,所有注册都是单例的:

var registrations = container
    .GetTypesToRegister(typeof(IPlayer), assemblies)
    .Select(t => Lifestyle.Singleton.CreateRegistration(t, container));


foreach (var registration in registrations)
{
    container.AddRegistration(registration.ImplementationType, registration);
}

container.RegisterCollection<IPlayer>(registrations);
container.RegisterCollection<ISongAware>(container.GetCurrentRegistrations()
    .Where(ip => typeof(ISongAware).IsAssignableFrom(ip.ServiceType))
    .Select(ip => ip.Registration));

问题

全部

必须return同一个实例,所以IPlayer注册必须是单例的。这样做,所有 PlayerEqualizer 也必须是单例,因为它们是单例注册的依赖项,但 PlayerEqualizer 实现不是单例(RockPlayerRnBPlayer 两者取决于 RockPlayerEqualizer 但他们需要不同的实例)。

我试过的

我能找到的唯一解决方案是将 SimpleInjector container.Options.SuppressLifestyleMismatchVerification 标志设置为 False 但我不想失去该功能...另一个选项可以调用 SuppressDiagnosticWarning 方法在 IPlayer 的注册上,但尽管我无法让它工作,但我真正担心的是这些解决方案只是解决方法...

我是不是漏掉了什么?

您想要的是 而不是 PlayerEqualizer 个实例注册为 Transient but as Instance Per Dependency

从技术上讲,这两种生活方式是相同的,因为它们都 return 在每个请求上创建新实例。然而,Instance per Dependencyintend 非常 不同,因为:

Each consumer will get a new instance of the given service type and that dependency is expected to get live as long as its consuming type.

虽然 Transient 的目的是短暂的依赖。

这种生活方式被故意排除在 Simple Injector 之外,因为:

its usefulness is very limited compared to the Transient lifestyle. It ignores lifestyle mismatch checks and this can easily lead to errors, and it ignores the fact that application components should be immutable. In case a component is immutable, it’s very unlikely that each consumer requires its own instance of the injected dependency.

然而,该项目的代码示例包含一个 InstancePerDependencyLifestyle 的定义,它可以执行您希望它执行的操作:

  • 它为每个消费者提供了自己的实例
  • 它忽略了注册时的生活方式不匹配,因为实例预计与其消费者一样长寿

您可以按照以下方式使用这种生活方式:

container.Register<RockPlayerEqualizer>(new InstancePerDependencyLifestyle());

更新:

请注意,您的配置可以简化为以下内容:

var playerTypes = var registrations = container
    .GetTypesToRegister(typeof(IPlayer), assemblies);

foreach (Type playerType in playerTypes)
{
    container.Register(playerType, Lifestyle.Singleton);
}

container.RegisterCollection<IPlayer>(assemblies);
container.RegisterCollection<ISongAware>(assemblies);