开发者

Castle Windsor registration of open generic decorator types

I am trying to figure out how to register decorators for generic types with 2 generic parameters. The first test case below is just a sanity check for a 1-generic parameter case which I added when the 2-parameter case did not work as expected.

The third (failing) case with a 1-generic-parameter (contravariant this time) seems to indicate that Windsor treats co- and contravariant generic parameters differently, so my question is: What am I doing wrong here?

I'm using .NET 4.0.

    [Test]
    public void RepoSingleGenericTest()
    {
        var windsorContainer = new Castle.Windsor.WindsorContainer();

        windsorContainer
            .Register(AllTypes.Of(typeof(IRepoSingle<>))
            .FromAssembly(typeof(StringRepoSingle).Assembly)
            .If(t => typeof(CachingRepoSingle<>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(IRepoSingle<>)));

        windsorContainer
            .Register(AllTypes.Of(typeof(IRepoSingle<>))
            .From开发者_StackOverflowAssembly(typeof(BoolRepoSingle).Assembly)
            .Unless(t => typeof(CachingRepoSingle<>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(IRepoSingle<>)));

        var stringRepo = windsorContainer.Resolve<IRepoSingle<string>>();
        Assert.IsInstanceOf<StringRepoSingle>(stringRepo);

        var boolRepo = windsorContainer.Resolve<IRepoSingle<bool>>();
        Assert.IsInstanceOf<BoolRepoSingle>(boolRepo);
    }

    [Test]
    public void RepoDoublyGenericTest()
    {
        var windsorContainer = new Castle.Windsor.WindsorContainer();

        windsorContainer
            .Register(AllTypes.Of(typeof(IRepoDoublyGeneric<,>))
            .FromAssembly(typeof(StringRepoDoublyGeneric).Assembly)
            .If(t => typeof(CachingRepoDoublyGeneric<,>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(IRepoDoublyGeneric<,>)));

        windsorContainer
            .Register(AllTypes.Of(typeof(IRepoDoublyGeneric<,>))
            .FromAssembly(typeof(DateTimeRepoDoublyGeneric).Assembly)
            .Unless(t => typeof(CachingRepoDoublyGeneric<,>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(IRepoDoublyGeneric<,>)));

        var stringRepo = windsorContainer.Resolve<IRepoDoublyGeneric<Guid, string>>();
        Assert.IsInstanceOf<CachingRepoDoublyGeneric<Guid, string>>(stringRepo);

        var dateTimeRepo = windsorContainer.Resolve<IRepoDoublyGeneric<Guid, DateTime>>();
        Assert.IsInstanceOf<CachingRepoDoublyGeneric<Guid, DateTime>>(dateTimeRepo);
    }

    [Test]
    public void CommandTest()
    {
        var windsorContainer = new Castle.Windsor.WindsorContainer();

        windsorContainer
            .Register(AllTypes.Of(typeof(ICommand<>))
            .FromAssembly(typeof(GuidCommand).Assembly)
            .If(t => typeof(DecoratorCommand<>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(ICommand<>)));

        windsorContainer
            .Register(AllTypes.Of(typeof(ICommand<>))
            .FromAssembly(typeof(StringCommand).Assembly)
            .Unless(t => typeof(DecoratorCommand<>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(ICommand<>)));

        var stringComand = windsorContainer.Resolve<ICommand<string>>();
        Assert.IsInstanceOf<DecoratorCommand<string>>(stringComand);

        var guidCommand = windsorContainer.Resolve<ICommand<Guid>>();
        Assert.IsInstanceOf<DecoratorCommand<Guid>>(guidCommand);
    }

    public interface IRepoSingle<out TValue>
    {
        TValue Get();
    }

    public class StringRepoSingle : IRepoSingle<string>
    {
        public string Get()
        {
            throw new NotImplementedException();
        }
    }

    public class BoolRepoSingle : IRepoSingle<bool>
    {
        public bool Get()
        {
            throw new NotImplementedException();
        }
    }

    public class CachingRepoSingle<T> : IRepoSingle<T>
    {
        private readonly IRepoSingle<T> realRepo;

        public CachingRepoSingle(IRepoSingle<T> realRepo)
        {
            if (realRepo == null) throw new ArgumentNullException("realRepo");

            this.realRepo = realRepo;
        }

        public T Get()
        {
            throw new NotImplementedException();
        }
    }

    public interface IRepoDoublyGeneric<in TKey, out TValue>
    {
        TValue Get(TKey key);
    }

    public class StringRepoDoublyGeneric : IRepoDoublyGeneric<Guid, string>
    {
        public string Get(Guid key)
        {
            throw new NotImplementedException();
        }
    }

    public class DateTimeRepoDoublyGeneric : IRepoDoublyGeneric<Guid, DateTime>
    {
        public DateTime Get(Guid key)
        {
            throw new NotImplementedException();
        }
    }

    public class CachingRepoDoublyGeneric<TKey, TValue> : IRepoDoublyGeneric<TKey, TValue>
    {
        private readonly IRepoDoublyGeneric<TKey, TValue> realRepo;

        public CachingRepoDoublyGeneric(IRepoDoublyGeneric<TKey, TValue> realRepo)
        {
            if (realRepo == null) throw new ArgumentNullException("realRepo");

            this.realRepo = realRepo;
        }

        public TValue Get(TKey key)
        {
            throw new NotImplementedException();
        }
    }

    public interface ICommand<in T>
    {
        void Do(T t);
    }

    public class StringCommand : ICommand<string>
    {
        public void Do(string t)
        {
            throw new NotImplementedException();
        }
    }

    public class GuidCommand : ICommand<Guid>
    {
        public void Do(Guid t)
        {
            throw new NotImplementedException();
        }
    }

    public class DecoratorCommand<T> : ICommand<T>
    {
        private readonly ICommand<T> realComamnd;

        public DecoratorCommand(ICommand<T> realComamnd)
        {
            if (realComamnd == null) throw new ArgumentNullException("realComamnd");

            this.realComamnd = realComamnd;
        }

        public void Do(T t)
        {
            throw new NotImplementedException();
        }
    }

UPDATE: The following does the trick, but I can't say I think it is the most elegant solution...:

        [Test]
    public void RepoDoublyGenericWithReflection()
    {
        var windsorContainer = new Castle.Windsor.WindsorContainer();

        // Register components for a caching decorator for all types implementing IRepoDoublyGeneric<,> - except for the generic cache itself
        (from t in typeof (DateTimeRepoDoublyGeneric).Assembly.GetTypes()
            let iRepo = t.GetInterfaces().SingleOrDefault( i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRepoDoublyGeneric<,>))
            where
                t.IsClass && !t.IsAbstract && !typeof(CachingRepoDoublyGeneric<,>).IsAssignableFrom(t)
                && iRepo != null
            select iRepo)
         .ForEach(rt => 
             windsorContainer.Register(Component.For(rt).ImplementedBy((typeof(CachingRepoDoublyGeneric<,>)).MakeGenericType(rt.GetGenericArguments()))) 
         );

        // Real repositories
        windsorContainer.Register(
            AllTypes.Of(typeof(IRepoDoublyGeneric<,>))
            .FromAssembly(typeof(DateTimeRepoDoublyGeneric).Assembly)
            .Unless(t => typeof(CachingRepoDoublyGeneric<,>).IsAssignableFrom(t))
            .WithService.FromInterface(typeof(IRepoDoublyGeneric<,>))
        );

        var stringRepo = windsorContainer.Resolve<IRepoDoublyGeneric<Guid, string>>();
        Assert.IsInstanceOf<CachingRepoDoublyGeneric<Guid, string>>(stringRepo);

        var dateTimeRepo = windsorContainer.Resolve<IRepoDoublyGeneric<Guid, DateTime>>();
        Assert.IsInstanceOf<CachingRepoDoublyGeneric<Guid, DateTime>>(dateTimeRepo);
    }

Following Krzysztof's suggestions, I've also tried:

        [Test]
    public void CommandTestUsingBasedOn()
    {
        var windsorContainer = new Castle.Windsor.WindsorContainer();

        windsorContainer
            .Register(AllTypes.Of(typeof(ICommand<>))
            .FromAssembly(typeof(GuidCommand).Assembly)
            .If(t => typeof(DecoratorCommand<>).IsAssignableFrom(t))
            .BasedOn(typeof(ICommand<>))
            .WithService.Base());

        windsorContainer
            .Register(AllTypes.Of(typeof(ICommand<>))
            .FromAssembly(typeof(StringCommand).Assembly)
            .Unless(t => typeof(DecoratorCommand<>).IsAssignableFrom(t))
            .BasedOn(typeof(ICommand<>))
            .WithService.Base());

        var stringComand = windsorContainer.Resolve<ICommand<string>>();
        Assert.IsInstanceOf<DecoratorCommand<string>>(stringComand);

        var guidCommand = windsorContainer.Resolve<ICommand<Guid>>();
        Assert.IsInstanceOf<DecoratorCommand<Guid>>(guidCommand);
    }
  • but that does not change the behavior.


Does it work when you register it as AllTypes.BasedOn(typeof(typeof(ICommand<>)) and WithService.Base()?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜