Castle Windsor 到 Unity - 在 Unity 中是否可以像在 CW 中一样自动配置?

6
我不知道这是否是太具体的问题,如果可能的话,但我需要转换一个使用Castle Windsor的应用程序到Unity,以便不依赖于非 Microsoft 批准的库。我知道我知道,但你会怎么做。

无论如何,我已经处理了,但我对自己得到的结果并不满意。在Windsor中,我有这样的代码:

Register(
            AllTypes.Of(typeof(AbstractPresenter<>)).FromAssemblyNamed("Links.Mvp"),
            AllTypes.Of(typeof(IView)).FromAssemblyNamed("Links.WinForms").WithService.FromInterface());

我已将其在Unity中转换为以下内容。
RegisterType<IMainView, MainView>();
        RegisterType<IConfigureLinkView, ConfigureLinkView>();
        RegisterType<IConfigureSourceView, ConfigureSourceView>();
        RegisterType<IConfigureSinkView, ConfigureSinkView>();
        RegisterType<MainPresenter, MainPresenter>();
        RegisterType<ConfigureLinkPresenter, ConfigureLinkPresenter>();
        RegisterType<ConfigureSourcePresenter, ConfigureSourcePresenter>();
        RegisterType<ConfigureSinkPresenter, ConfigureSinkPresenter>();

你可以看到,我不得不注册每一个东西,而不能使用某种自动配置。所以我的问题是:在Unity中有更好的方法吗?

谢谢,

Adam。


一个想法是从CastleWindsor的源代码中删除用于Register()的代码,并从Unity容器中制作扩展方法。 - eduncan911
如果你要转到Unity,请接受我的慰问。这将是痛苦的世界,特别是如果你在Windsor方面有广泛而复杂的经验。 - Krzysztof Kozmic
5个回答

5

看看这个


        var container = new UnityContainer();

        container
            .ConfigureAutoRegistration()
            .LoadAssemblyFrom("Plugin.dll")
            .IncludeAllLoadedAssemblies()
            .ExcludeSystemAssemblies()
            .ExcludeAssemblies(a => a.GetName().FullName.Contains("Test"))
            .Include(If.Implements<ILogger>, Then.Register().UsingPerCallMode())
            .Include(If.ImplementsITypeName, Then.Register().WithTypeName())
            .Include(If.Implements<ICustomerRepository>, Then.Register().WithName("Sample"))
            .Include(If.Implements<IOrderRepository>,
                     Then.Register().AsSingleInterfaceOfType().UsingPerCallMode())
            .Include(If.DecoratedWith<LoggerAttribute>,
                     Then.Register()
                            .AsInterface<IDisposable>()
                            .WithTypeName()
                            .UsingLifetime<MyLifetimeManager>())
            .Exclude(t => t.Name.Contains("Trace"))
            .ApplyAutoRegistration();

无耻的自我推销!我喜欢它。 - smaclell
还有非常好的源代码。如果我必须使用Unity,我一定会包含它;)。 - smaclell

2
Unity 3 现在支持开箱即用的按约定注册功能。
下面的代码将会把所有具体实现类映射到遵循约定的接口:IFoo -> Foo。
var container = new UnityContainer();
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    WithName.Default);

顺便说一下,如果具体类型类不映射到其他类型,则无需注册它们(就像您的XXXPresenter类一样)... 如果一个类依赖于具体类型,Unity会自动构建它。
您可以使用约定做更多的事情,比如过滤要使用哪些程序集或类型,或者如何进行映射,但我建议您查看MSDN中的示例,因为它们涵盖了其中的几个方面。

http://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx#sec23


0

我刚刚偶然发现了这个问题,正在寻找有关Windsor基于约定的注册信息的信息,虽然这是一个相当古老的问题,但我认为我会留下一个答案,供其他可能在Unity中寻找此类功能的人使用。

去年,我为Unity编写了一个基于约定的注册扩展,您可以在这里阅读有关它的信息。实际下载可在google code 这里获得。基本用法如下:

  _container
        .Using<IConventionExtension>()
        .Configure(x =>
            {
                x.Conventions.Add<InterfaceImplementionNameMatchConvention>();
                x.Assemblies.Add(Assembly.GetExecutingAssembly());
            })
        .Register();

还有一个ClosingTypeConvention,用来自动注册开放泛型类型:

  _container
                .Using<IConventionExtension>()
                .Configure(x =>
                    {
                        x.Conventions.Add(new ClosingTypeConvention(typeof (IRepository<>)));
                        x.Assemblies.Add(Assembly.GetExecutingAssembly());
                    })
                .Register();

0

很酷。这个功能还没有在Unity中实现,但如果你有点雄心壮志,你可以设置自己的基于约定的注册。下面是一个适用于执行程序和接口的代码片段。祝你好运。

顺便说一句,这感觉像是一个大型黑客攻击,我可能会继续手动注册所有类型。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;

namespace Forum
{
    class Program
    {
        static void Main(string[] args)
        {
            // get your assemblies and types you can register
            Assembly a = Assembly.GetExecutingAssembly();
            var types = a.GetTypes();            
            var bindTo = from t in types
                         where t.IsAbstract || t.IsInterface
                         select t;

            // apply your conventions to filter our types to be registered
            var interfacePairs = from t in bindTo.Where(x => x.IsInterface)
                                 let match = types.FirstOrDefault(x => x.Name ==     t.Name.Substring(1))
                                 where match != null
                                 select new Pair { To = t, From = match };
            var abstractPairs = new Pair[] {};


            // setup the generic form of the method to register the types
            var thisType = typeof(Program);
            var bindings = BindingFlags.Static | BindingFlags.Public;
            MethodInfo genericMethod = thisType.GetMethod("RegisterType", bindings);            

            // register all your types by executing the 
            // specialized generic form of the method
            foreach (var t in interfacePairs.Concat(abstractPairs))
            {
                Type[] genericArguments = new Type[] { t.To, t.From };
                MethodInfo method = genericMethod.MakeGenericMethod(genericArguments);
                method.Invoke(null, new object [] {});
            }

            Console.ReadKey();
        }

        public static void RegisterType<To, From>()
        {
            Console.WriteLine("Register { To: {0} From: {1} }", typeof(To), typeof(From));
        }

        // Test classes that should be picked up
        interface ITest { }
        class Test : ITest { }

        class Pair
        {
            public Type To { get; set; }
            public Type From { get; set; }
        }        
    }
}

1
这并不是什么黑客行为,因为CastleWindsor的源代码也做了类似的事情(尽管更加优雅)。对于他来说,更好的想法是剥离用于Register()的代码,并从Unity容器中制作一个扩展方法。 - eduncan911
我理解你的意思是将它从Windsor中取出,然后应用到Unity中?当然可以!嗯...优雅?也许下一个项目吧 ;)。 - smaclell

-1
据我所知,在Unity中没有办法做到这一点。Unity比Windsor容器成熟度低,架构也不如后者,因此许多事情在Unity中更加困难或不可能实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接