简单注入器 - 具有瞬态依赖设计的单体

时间:2017-12-03 16:13:45

标签: c# wpf inversion-of-control simple-injector

上下文

我知道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));

问题

全部

  • container.GetInstance<RockPlayer>
  • container.GetAllInstances<IPlayer>
  • container.GetAllInstances<ISongAware>

必须返回相同的实例,因此IPlayer注册必须是单例。这样做,所有PlayerEqualizer也必须是单例,因为它们是单例注册的依赖关系,但PlayerEqualizer实现不是单例(RockPlayerRnBPlayer两者取决于RockPlayerEqualizer,但它们需要不同的实例。)

我尝试了什么

我能找到的唯一解决方案是将SimpleInjector container.Options.SuppressLifestyleMismatchVerification标志设置为False,但我不想丢失该功能......另一种选择是调用SuppressDiagnosticWarning关于IPlayer注册的方法,但是尽管我无法使用它,我真正关心的是这些解决方案只是解决方法......

我错过了什么吗?

1 个答案:

答案 0 :(得分:0)

你想要的是PlayerEqualizer个实例注册为Transient,而是Instance Per Dependency

从技术上讲,两种生活方式都是一样的,因为它们都会在每次请求时都返回新的实例。然而,每个依赖性实例的意图 非常不同,因为:

  

每个使用者都将获得给定服务类型的新实例,并且只要其消费类型,该依赖关系就会生效。

使用 Transient 时,意图是依赖是短暂的。

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

  

与Transient生活方式相比,它的用处非常有限。它忽略了生活方式不匹配检查,这很容易导致错误,并忽略了应用程序组件应该是不可变的这一事实。如果一个组件是不可变的,那么每个消费者都不太可能需要它自己的注入依赖项实例。

项目的代码示例包含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);