Search code examples
c#autofacautofac-configuration

How to register decorator to be able to resolve decoree


I'm using Autofac. I'm trying to register 2 classes with same interface using decorator pattern.

public interface IDoable
{
    string Do();
}

public class Decoree : IDoable
{
    public string Do()
    {
        return "decoree";
    }
}

public class Decorator : IDoable
{
    public IDoable InnerDecoree { get; set; }

    public Decorator(IDoable doable)
    {
        this.InnerDecoree = doable;
    }

    public string Do()
    {
        return InnerDecoree.Do() + "decorator";
    }
}

I'd like to use container for resolving two types for 2 different cases:

  • IDoable where I'd expect that instance would be instance of Decorator
  • and for specific Decoree where I really need to resolve specific Decoree instance.

Only way how I can achieve it is using following code:

[Fact]
public void Both()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<Decoree>()
           .Named<IDoable>("decoree")
           .SingleInstance();

    builder.RegisterType<Decoree>() // but this is not right I'd like to register it on line above somehow...
        .AsSelf()
        .SingleInstance(); 

    builder.RegisterType<Decorator>()
           .Named<IDoable>("decorator")
           .SingleInstance();

    builder.RegisterDecorator<IDoable>(
            (c, inner) => c.ResolveNamed<IDoable>("decorator", TypedParameter.From(inner)), "decoree")
            .As<IDoable>();

    var container = builder.Build();

    Assert.IsType<Decoree>(container.Resolve<Decoree>());
    Assert.False(container.IsRegistered<Decorator>());
    Assert.IsType<Decorator>(container.Resolve<IDoable>());


    var decoree = container.Resolve<Decoree>();
    var decorator = container.Resolve<IDoable>();
    var doable = ((Decorator)decorator).InnerDecoree;

    Assert.Same(decoree, doable); // FALSE :(

}

The thing is that I'd really love the last assertion to be true :) so It's same instance.

Basically my question is: Is it possible to register type both ways using named and type ?


Solution

  • Because you aren't specifying a scope in your registration, you are getting a different instance of Decoree every time it gets resolved. I would try something like

    builder.RegisterType<Decoree>()
           .Named<IDoable>("decoree").SingleInstance();
    

    In addition, you might need to combine your 2 registrations of the Decoree type:

    builder.RegisterType<Decoree>()
           .Named<IDoable>("decoree")
           .AsSelf()
           .SingleInstance();