Skip to content

Generics

Peter Csajtai edited this page Jun 30, 2020 · 21 revisions

With stashbox you have the option to register open generic types, which gives you the flexibility of choosing the closed generic parameter later at resolution time.

interface IDrow<TLeftHand, TRightHand> 
{
}

class Drow<TLeftHand, TRightHand> : IDrow<TLeftHand, TRightHand> 
{
    public Drow(TLeftHand leftHand, TRightHand rightHand)
    {
    }
}

container.Register(typeof(IDrow<,>), typeof(Drow<,>))
         .Register<Twinkle>()
         .Register<Icingdeath>();

var drizzt = container.Resolve<IDrow<Twinkle, Icingdeath>>();

A registered concrete generic type has always priority over an open generic type.

Dependency selection by contraints

The dependencies of the generic services are choosed by matching to their generic argument constraints.

interface IConstraint { }
interface IConstraint1 { }
interface IConstraintTest<T> { }

class ConstraintTest<T> : IConstraintTest<T> where T : IConstraint { }
class ConstraintTest1<T> : IConstraintTest<T> where T : IConstraint1 { }
class ConstraintArgument : IConstraint1 { }

using (var container = new StashboxContainer())
{
     var inst = container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest<>))
                         .Register(typeof(IConstraintTest<>), typeof(ConstraintTest1<>))
                         .Resolve<IConstraintTest<ConstraintArgument>>();

     Assert.IsInstanceOfType(inst, typeof(ConstraintTest1<ConstraintArgument>));
}

The example above shows that the container chooses ConstraintTest1 because its generic argument constraint matches the interface implemented by the requested ConstraintArgument.

Collection filters by constraints

using (var container = new StashboxContainer())
{
    var inst = container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest<>));
                        .Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>))
                        .ResolveAll<IConstraintTest<ConstraintArgument>>().ToArray();

    Assert.AreEqual(1, inst.Length);
}

The example above shows that the container filters out those services from the returned collection whichs constraint doesn't allow the resolution of the given closed generic type.