Let's say I have the following classes that implement the following interfaces:
class MyClassA : IInterface<MyClassA>, IInterface
class MyClassB : IInterface<MyClassB>, IInterface
I have two other classes like the following:
class ImportA {
public ImportA(IEnumerable<IInterface>) {}
}
class ImportB {
public ImportB(IInterface<MyClassA>) {}
}
IInterface
in my assembly.IInterface<MyClassA>
.I can't figure out how to get this to work with Simple Injector. I've tried RegisterCollection
and https://simpleinjector.readthedocs.org/en/latest/howto.html#register-multiple-interfaces-with-the-same-implementation
The closest I have come is getting an error saying one class imported as Singleton the other as Transient.
I've tried changing all the LifeStyles to Singleton and setting the config to Singleton by default, to no avail.
UPDATE 1: I am looking for an automated approach. I have a lot of classes to register and don't want to have to do it by hand. Here is a different sample. The below registration examples didn't work. The automated one failed with:
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>>?
Here is my current code:
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));
}
ImportA is the entry point and should be Transient. Everything else should be singleton so that when MyClassA is modified in ImportA the value is picked up in MyClassB.
The way to do this is by creating Registration
instances manually and use them to register two separate collections. Example:
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);
This will ensure that the same single instance is used in both collections. If a class implements multiple generic versions of IInterface<T>
, that same single instance will even be reused over the different collections for IInterface<T>
.
If you want a more automated approach, you can do this:
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);
}