Enterprise Library 5.0のデフォルトのDIコンテナのUnityが便利そうではあるんだけどMEFみたいに属性でコンテナに登録ができないっぽい。ということで、こんなのでっちあげてみた。
自動登録したいクラスにこの属性をつけると登録されるみたいな感じ。
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class AutoRegistAttribute : Attribute { private static readonly InjectionMember[] InjectionMembersInitialValue = new InjectionMember[0]; public AutoRegistAttribute() { this.InjectionMembers = InjectionMembersInitialValue; } public string Name { get; set; } public Type RegisterType { get; set; } public InjectionMember[] InjectionMembers { get; set; } }
んで、この属性がついてるものをコンテナに登録する拡張。
public class AutoRegisterExtension : UnityContainerExtension { private Assembly[] loadTargets; public AutoRegisterExtension(params Assembly[] loadTargets) { this.loadTargets = loadTargets; } protected override void Initialize() { var targetTypes = loadTargets.SelectMany(assembly => assembly.GetTypes()) .Where(type => type.GetCustomAttributes(typeof(AutoRegistAttribute), false).Any()) .Select(type => new { Type = type, Attribute = type.GetCustomAttributes(typeof(AutoRegistAttribute), false).OfType<AutoRegistAttribute>().First() }); foreach (var type in targetTypes) { var registerType = type.Attribute.RegisterType ?? type.Type; if (string.IsNullOrEmpty(type.Attribute.Name)) { this.Container.RegisterType(registerType, type.Type, type.Attribute.InjectionMembers); } else { this.Container.RegisterType(registerType, type.Type, type.Attribute.Name, type.Attribute.InjectionMembers); } } } }
使ってみよう
使い方は割と簡単。登録したいクラスに属性をつけるだけ。
public interface IGreeter { void Greet(); } [AutoRegist(RegisterType = typeof(IGreeter))] public class Greeter : IGreeter { public void Greet() { Console.WriteLine("Hello world"); } } [AutoRegist] public class Client { [Dependency] public IGreeter Greeter { get; set; } public void Execute() { this.Greeter.Greet(); } }
そして、Mainメソッドの中でこんな感じに使う。
var container = new UnityContainer() .AddExtension(new AutoRegisterExtension(Assembly.GetExecutingAssembly())); var client = container.Resolve<Client>(); client.Execute();
これで、少しは楽が出来るかな。というか、何でこういうのが無いんだろうか?Unityのポリシー?