How to setup a Unity Registration Convention?

前端 未结 1 1528
一个人的身影
一个人的身影 2021-02-20 17:54

With structure map, you can register a convention that lets you not just tweak the type, but also intervene during object creation. How can I do this with Unity.



        
相关标签:
1条回答
  • 2021-02-20 18:31

    You can do this with a combination of Unity's Registration by Convention and an InjectionFactory. I see three common options for implementation, though I'm sure there are more...


    Option 1

    Register all type at once with if conditions inline in a lambda expression. Though this does not scale well if you are registering many types with many custom registrations...

    container.RegisterTypes(
        AllClasses.FromLoadedAssemblies(),
        WithMappings.FromAllInterfaces,
        WithName.Default,
        WithLifetime.Transient,
        type =>
        {
            // If settings type, load the setting
            if (!type.IsAbstract && typeof (ISettings).IsAssignableFrom(type))
            {
                return new[]
                {
                    new InjectionFactory((c, t, n) =>
                    {
                        var svc = (ISettings) c.Resolve(t);
                        return svc.LoadSetting(t);
                    })
                };
            }
    
            // Otherwise, no special consideration is needed
            return new InjectionMember[0];
        });
    

    Option 2

    Register only the ISettings types and supply some nice helper methods. You will need to call container.RegisterTypes multiple times, but it is much more readable...

    container.RegisterTypes(
        AllClasses.FromLoadedAssemblies().IsSetting(),
        WithMappings.FromAllInterfaces,
        WithName.Default,
        WithLifetime.Transient,
        SettingsRegistration.InjectionMembers);
    
    ...
    
    public static class SettingsRegistration
    {
        public static IEnumerable<Type> IsSetting(this IEnumerable<Type> types)
        {
            return types.Where(type => !type.IsAbstract && 
                                       typeof (ISettings).IsAssignableFrom(type));
        }
    
        public static IEnumerable<InjectionMember> InjectionMembers(Type type)
        {
            return new[] {new InjectionFactory(LoadSetting)};
        }
    
        public static ISettings LoadSetting(IUnityContainer container, 
                                            Type type, 
                                            string name)
        {
            var svc = (ISettings) container.Resolve(type, name);
            return svc.LoadSetting(type);
        }
    }
    

    Option 3

    Or you could create a class derived from RegistrationConvention and let that class make all of the registration decisions...

    container.RegisterTypes(new SettingsRegistrationConvention(
        AllClasses.FromLoadedAssemblies()));
    
    ...
    
    public class SettingsRegistrationConvention : RegistrationConvention
    {
        private readonly IEnumerable<Type> _scanTypes;
    
        public SettingsRegistrationConvention(IEnumerable<Type> scanTypes)
        {
            if (scanTypes == null)
                throw new ArgumentNullException("scanTypes");
    
            _scanTypes = scanTypes;
        }
    
        public override IEnumerable<Type> GetTypes()
        {
            return _scanTypes.Where(type => !type.IsAbstract && 
                                            typeof (ISettings).IsAssignableFrom(type));
        }
    
        public override Func<Type, IEnumerable<Type>> GetFromTypes()
        {
            return WithMappings.FromAllInterfaces;
        }
    
        public override Func<Type, string> GetName()
        {
            return WithName.Default;
        }
    
        public override Func<Type, LifetimeManager> GetLifetimeManager()
        {
            return WithLifetime.Transient;
        }
    
        public override Func<Type, IEnumerable<InjectionMember>> GetInjectionMembers()
        {
            return type => new[]
            {
                new InjectionFactory((c, t, n) =>
                {
                    var svc = (ISettings) c.Resolve(t);
                    return svc.LoadSetting(t);
                })
            };
        }
    }
    
    0 讨论(0)
提交回复
热议问题