0

I'm using Castle Windsor and I'm trying to set up a cache on a TypedFactory using the decorator pattern. It works fine until I'm trying to dispose of the Windsor container (when shutting down the application). Basically, my problem is that the TypedFactory is already disposed when I'm trying to dispose of the CachedFactory.

Here is a simplified example of my problem:

using System;
using System.Collections.Generic;
using System.Threading;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            // Setting up the container
            var container = new WindsorContainer();
            container.AddFacility<TypedFactoryFacility>();
            container.Register(
                Component.For<IItemFactory>().ImplementedBy<CachedItemFactory>(), //decorator pattern
                Component.For<IItemFactory>().AsFactory(),
                Component.For<IItem>().ImplementedBy<Item>().LifestyleTransient()
                );

            // Resolving
            var itemFactory = container.Resolve<IItemFactory>();

            // Desired behavior. Works as expected.
            IItem item1 = itemFactory.Create("Item1");
            IItem item2 = itemFactory.Create("Item2");
            IItem anotherItem1 = itemFactory.Create("Item1");
            Console.WriteLine("Item1 == Item2: {0}", item1 == item2); //false
            Console.WriteLine("Item1 == anotherItem1: {0}", item1 == anotherItem1); //true

            // Here is my problem. It throws ObjectDisposedException from _itemFactory in the Dispose function of CachedItemFactory
            container.Dispose();

            Console.WriteLine("End of program");
            Console.ReadKey();
        }
    }

    public interface IItem
    {
        string Name { get; }
    }

    public class Item : IItem
    {
        public Item(string name)
        {
            Name = name;
            Thread.Sleep(1000); //It takes time to create this object
        }

        public string Name { get; private set; }
    }

    public interface IItemFactory
    {
        IItem Create(string name);
        void Release(IItem item);
    }

    public class CachedItemFactory : IItemFactory, IDisposable
    {
        private readonly Dictionary<string, IItem> _cache = new Dictionary<string, IItem>();
        private readonly IItemFactory _itemFactory;

        public CachedItemFactory(IItemFactory itemFactory)
        {
            _itemFactory = itemFactory;
        }

        public IItem Create(string name)
        {
            if (!_cache.ContainsKey(name))
                _cache.Add(name, _itemFactory.Create(name));
            return _cache[name];
        }

        public void Release(IItem item)
        {
        }

        public void Dispose()
        {
            foreach (var item in _cache)
            {
                _itemFactory.Release(item.Value);
            }
            _cache.Clear();
        }
    }
}

Any ideas of what I'm doing wrong? Any conceptual (architectural) errors?

I tried the following with no success:

  1. Registering the TypedFactory before the CachedItemFactory (and marking the CachedItemFactory as IsDefault): not working, same error
  2. Implementing a basic factory by hand instead of using the TypedFactory: same problem

This worked:

  1. Implementing a basic factory by hand, registering it before the CachedItemFactory and marking the CachedItemFactory as IsDefault... but it feels wrong (fragile)...

Any comments?

Thanks a lot!

4

1 回答 1

0

您将缓存和类型化工厂都注册为单例(隐式)。如果您将 TypeFactory 注册为 Transient,它可能会(不完全确定)在缓存工厂之后立即处理。

但是,由于您只尝试清理工厂的已解析组件,您也可以简单地省略 Dispose 中的代码,因为类型化工厂将在发布时释放它的所有组件。

于 2013-06-11T08:36:19.317 回答