温莎城堡注册开放通用装饰器类型

发布于 2024-10-03 11:39:15 字数 9304 浏览 2 评论 0原文

我试图弄清楚如何使用 2 个泛型参数为泛型类型注册装饰器。下面的第一个测试用例只是对 1 通用参数情况的健全性检查,当 2 参数情况未按预期工作时我添加了该情况。

第三个(失败)带有 1-generic-parameter(这次是逆变)的情况似乎表明 Windsor 对待协泛型参数和逆变泛型参数的方式不同,所以我的问题是:我在这里做错了什么?

我正在使用.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<>))
            .FromAssembly(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();
        }
    }

更新:以下方法可以解决问题,但我不能说我认为这是最优雅的解决方案...:

        [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);
    }

按照 Krzysztof 的建议,我也尝试过:

        [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);
    }
  • 但这并没有改变行为。

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<>))
            .FromAssembly(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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

牵你手 2024-10-10 11:39:16

当您将其注册为 AllTypes.BasedOn(typeof(typeof(ICommand<>))WithService.Base() 时,它是否有效?

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文