This project is read-only.

bug in IsDecorateeDependencyParameterType() ?

Jan 2, 2015 at 8:35 PM
shouldn't the following check:
return
(serviceType.ContainsGenericParameters || parameterType.IsGenericType) &&
serviceType.GetGenericTypeDefinition() == parameterType.GetGenericTypeDefinition();

instead be:

return
(serviceType.ContainsGenericParameters && parameterType.ContainsGenericParameters) &&
serviceType.GetGenericTypeDefinition() == parameterType.GetGenericTypeDefinition();

the current version of the code will not let you register a class as a decorator for 2 different generic types.
Jan 2, 2015 at 8:50 PM
Hi,

can you give us some context - where is this code from?
Jan 2, 2015 at 11:05 PM
Can you demonstrate this bug with some code? Code in the form of a unit test would be ideal for instance.
Jan 2, 2015 at 11:20 PM
Ah, I found it - it's actually named IsDecorateeDependencyParameter. I'll take a look at this tomorrow.
Jan 3, 2015 at 1:19 AM
Glad you found the right method.

following is minimal code that reproduces the issue.

public interface IHandle<T>
{
void Handle(T message);
}

public class ShouldDecorateBothInterfaces
{
public ShouldDecorateBothInterfaces(IHandle<object> first, IHandle<string> second) {

}
}


//Note: SimpleInjector will throw an exception on the first register decorator call complaining that
//the ShouldDecorateBothInterfaces constructor should take a single parameter of the type that it decorates.
//Apparently it thinks that IHandle<string> and IHandle<object> are the same thing.
dependencyContainer.RegisterDecorator(typeof(IHandle<object>), typeof(ShouldDecorateBothInterfaces));
dependencyContainer.RegisterDecorator(typeof(IHandle<string>), typeof(ShouldDecorateBothInterfaces));


Jan 3, 2015 at 9:49 AM
Edited Jan 3, 2015 at 9:57 AM
Firstly ShouldDecorateBothInterfaces is not a decorator. A decorator needs to be of the same type as the type it is decorating.

Secondly, I can suggest 2 options:

Specific decorators
public class ShouldDecorateString : IHandle<string>
{
    public ShouldDecorateString(IHandle<string> decorated)
    {
    }

    //...
}

public class ShouldDecorateObject : IHandle<object>
{
    public ShouldDecorateObject(IHandle<object> decorated)
    {
    }

    // ...
}
or a generic decorator
public class ShouldDecorateStringOrObject<T> : IHandle<T>
{
    public ShouldDecorateStringOrObject(IHandle<T> decorated)
    {
    }

    // ...
}
with a delegate filter applied during registration
[Fact]
public void Register_DecoratorForStringAndObject_Succeeds()
{
    var container = new Container();
    container.RegisterOpenGeneric(typeof(IHandle<>), typeof(Handler<>));
    container.RegisterDecorator(
        typeof(IHandle<>),
        typeof(ShouldDecorateStringOrObject<>), 
        context => new Type[] { typeof(string), typeof(object) }
            .Contains(context.ServiceType.GetGenericArguments()[0]));

    var stringHandler = container.GetInstance<IHandle<string>>();
    var objectHandler = container.GetInstance<IHandle<object>>();
    var intHandler = container.GetInstance<IHandle<int>>();
    Assert.IsType<ShouldDecorateStringOrObject<string>>(stringHandler);
    Assert.IsType<ShouldDecorateStringOrObject<object>>(objectHandler);
    Assert.IsType<Handler<int>>(intHandler);
}
Jan 3, 2015 at 10:52 AM
Also, see this discussion for a known limitation when injecting multiple implementations of the same type into decorator. This will be addressed in the coming months.