简单注入器:具有多个接口的类的批量注册

本文关键字:注册 接口 注入器 简单 | 更新日期: 2023-09-27 18:31:36

假设我有以下实现以下接口的类:

class MyClassA : IInterface<MyClassA>, IInterface
class MyClassB : IInterface<MyClassB>, IInterface

我还有另外两个类,如下所示:

class ImportA {
    public ImportA(IEnumerable<IInterface>) {}
}
class ImportB {
    public ImportB(IInterface<MyClassA>) {}
}
  • 我希望将 ImportA 注入到在我的程序集中实现IInterface的每个类中。
  • 我希望 ImportB 只注入一个 IInterface<MyClassA> 实例。
  • 我希望来自两个方法的具体类 MyClassA 的实例是相同的(生命周期:单例)。

我不知道如何让它与简单注射器一起使用。我试过RegisterCollection和 https://simpleinjector.readthedocs.org/en/latest/howto.html#register-multiple-interfaces-with-the-same-implementation

我最接近的是收到一个错误,说一个类作为单例导入,另一个作为瞬态导入。

我尝试将所有生活方式更改为单例,并将配置默认设置为单例,但无济于事。

更新 1:我正在寻找一种自动化方法。我有很多课程要注册,不想手工注册。下面是一个不同的示例。下面的注册示例不起作用。自动化失败,并显示:

An exception of type 'SimpleInjector.ActivationException' occurred in  
SimpleInjector.dll but was not handled in user code
Additional information: The constructor of type MyClassB contains the 
parameter with name 'myClassA' and type IInterface<MyClassA> that is not 
registered. Please ensure IInterface<MyClassA> is registered, or change the 
constructor of MyClassB. There is, however, a registration for 
IEnumerable<IInterface<MyClassA>>; Did you mean to depend on 
IEnumerable<IInterface<MyClassA>>?

这是我当前的代码:

public interface IInterface {
  string Value { get; set; }
}
public interface IInterface<T> : IInterface { }
public class MyClassA : IInterface<MyClassA> {
  public string Value { get; set; }
}
public class MyClassB : IInterface<MyClassB> {
  private IInterface<MyClassA> myClassA;
  public MyClassB(IInterface<MyClassA> myClassA) {
    this.myClassA = myClassA;
  }
  public string Value {
    get { return this.myClassA.Value; }
    set { this.myClassA.Value = value; }
  }
}
public class ImportA {
  public ImportA(IEnumerable<IInterface> imports) {
    // fails on this line
    var a = imports.SingleOrDefault(i => i is IInterface<MyClassA>);
    a.Value = "test";
    var b = imports.SingleOrDefault(i => i is IInterface<MyClassB>);
    // should output the value of "test";
    Console.WriteLine(b.Value);
    Console.ReadKey();
  }
}
...
static void Main() {
  var container = new Container();
  var types = container.GetTypesToRegister(
    typeof(IInterface<>), new[] { typeof(IInterface<>).Assembly });
  var registrations = (
    from type in types
    select Lifestyle.Singleton.CreateRegistration(type, type, container))
    .ToArray();
  container.RegisterCollection<IInterface>(registrations);
  container.RegisterCollection(typeof(IInterface<>), registrations);
  var a = container.GetInstance(typeof(ImportA));
}

导入 A 是入口点,应该是暂时性的。其他所有内容都应该是单例的,以便在 ImportA 中修改 MyClassA 时,在 MyClassB 中选取值。

简单注入器:具有多个接口的类的批量注册

执行此操作

的方法是手动创建Registration实例并使用它们来注册两个单独的集合。例:

var a = Lifestyle.Singleton.CreateRegistration<MyClassA>(container);
var b = Lifestyle.Singleton.CreateRegistration<MyClassB>(container);
container.RegisterCollection<IInterface>(new[] { a, b });
container.AddRegistration(typeof(IInterface<MyClassA>), a);
container.AddRegistration(typeof(IInterface<MyClassB>), b);

这将确保在两个集合中使用相同的单个实例。如果一个类实现了IInterface<T>的多个泛型版本,那么同一个实例甚至会在不同的集合上重用IInterface<T>

如果你想要一种更自动化的方法,你可以这样做:

var types = container.GetTypesToRegister(typeof(IInterface<>), assemblies);
// NOTE: The ToArray() call is crucial to prevent torn lifestyles.
var registrations = (
    from type in types
    select Lifestyle.Singleton.CreateRegistration(type, type, container))
    .ToArray();
container.RegisterCollection<IInterface>(registrations);
foreach (var registration in registrations) {
    container.AddRegistration(
        typeof(IInterface<>).MakeGenericType(registration.ImplementationType),
        registration);
}