2
votes

I'm using Castle Windsor as an IoC container, and I want to resolve an object depending on another:

public MyService : IService
{
  public MyService(MyObject obj)
  {
  }
}

Where resolving with:

var service1 = container.Resolve<IService>( new { obj = obj1 });
var service2 = container.Resolve<IService>( new { obj = obj1 });

var service3 = container.Resolve<IService>( new { obj = obj2 });

I want service1 to be the same as service2 (same reference), and service3 different. So I need a lifestyle different than Singleton or Transient. The same object should be returned as long as the obj parameter is the same (by reference).

Do you know how to achieve that?

2
What is your exact use case? Why do you need this?Steven
Actually IService is a factory, and MyObject is an objet on which the factory depends (could be a WCF recieved objects).enenkey
Prevent doing constructor injection for runtime dependencies (as obj seems to be). Passing in values into the Resolve method is a design smell. If IService is a factory, pass in obj in to the factories CreateXXX method, since it is clearly part of the factories contract.Steven
@Steven I can't pass obj on the Create methods of the factories, that is adding unnecessary constructor overheads for all the objects that are using the factories.enenkey
If you can, please update your question with concrete examples of your code. This way we might be able to give you some feedback on your design. Improving your design could prevent you from having to implement a custom ILifestyleManager, which would probably save you tons of time.Steven

2 Answers

3
votes

I am not aware of a built-in solution, but you can always create your own ILifestyleManager.
For the reference, you can look at the implementation of SingletonLifestyleManager.

I never actually researched how to make custom lifestyles for Castle (we did one for Unity as far as I remember), but normally the idea is to decide when you want to resolve a new instance (CreateInstance in Castle code) and when to use the stored value.

ConcurrentDictionary can help with storage in your case (though no idea what Castle's burden does, you might want to research this). Beware of the leaks if your objs are created dynamically — you may be interested in ConditionalWeakTable.

Note: I agree with @Steven that in your case obj should normally be a parameter Create method, but just for the completeness I'll keep a direct answer as well.

2
votes

I finally created a IScopeAccessor like:

public class PerConstructorScopeAccessor : IScopeAccessor
{
    private static IDictionary<int, ILifetimeScope> Cache = new ConcurrentDictionary<int, ILifetimeScope>();

    public ILifetimeScope GetScope(Castle.MicroKernel.Context.CreationContext context)
    {
        int key = GetContextKey(context);
        if (!Cache.ContainsKey(key))
            Cache.Add(key, new DefaultLifetimeScope());

        return Cache[key];
    }

    private int GetContextKey(Castle.MicroKernel.Context.CreationContext context)
    {
        int hash = 0;

        foreach (var value in context.AdditionalArguments.Values)
        {
            hash = HashCode.CombineHashCode(hash, value.GetHashCode());
        }

        return hash;
    }

    #region IDisposable

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
}

And than I register my dependency using LifestyleScoped<PerConstructorScopeAccessor>()