Managed Extensibility FrameworkでAOP
個人的に.NET4で一番期待していたMEFですが、何か足りないなぁっと思っていたらAOPがサポートされていなかったんですね。twitterでつぶやいていた案でちょっと組んでみました。ExportProviderでごにょごにょ。ただ、まだ勉強のためのコードなのでこのまま仕事とかでは使えないと思います。(^^;
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Linq; using System.Reflection; using System.ComponentModel.Composition.Primitives; using Castle.Core.Interceptor; using Castle.DynamicProxy; namespace MEFAopSample { // テスト用のインタフェース public interface IGreeting { void Say(string msg); } // 簡単なインタフェースの実装 // MEFでエクスポート [Export(typeof(IGreeting))] public class Greeting : IGreeting { public void Say(string msg) { Console.WriteLine(msg); } } // インターセプタ public class SimpleInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { // メソッドの呼び出しの前後にメッセージを挟むだけの簡単な割り込み Console.WriteLine("Begin intercept..."); invocation.Proceed(); Console.WriteLine("End intercept."); } } // AOPを組み込んだエクスポートプロバイダ public class AopExportProvider : CatalogExportProvider { private readonly ProxyGenerator _generator = new ProxyGenerator(); private readonly Dictionary<Type, IInterceptor> _dic = new Dictionary<Type, IInterceptor>(); public void RegisterProxy(Type type, params IInterceptor interceptors) { _dic[type] = interceptors; } public AopExportProvider(ComposablePartCatalog catalog) : base(catalog) { } public AopExportProvider(ComposablePartCatalog catalog, bool isThreadSafe) : base(catalog, isThreadSafe) { } private object CreateProxy(object target) { foreach (Type key in _dic.Keys) { if (!key.IsInstanceOfType(target)) continue; return _generator.CreateInterfaceProxyWithTarget(key, target, _dic[key]); } return target; } protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { #pragma warning disable 1911 return from export in base.GetExportsCore(definition, atomicComposition) let export1 = export select new Export(export.Definition, () => CreateProxy(export1.Value)); } } [Export] public class Program { // MEFでインポートされる [Import] public IGreeting Greeting { get; set; } static void Main(string args) { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var ep = new AopExportProvider(catalog); // 対象となるインタフェースとインターセプタを登録 ep.RegisterProxy(typeof (IGreeting), new SimpleInterceptor()); var container = new CompositionContainer(ep); ep.SourceProvider = container; var program = container.GetExportedValue<Program>(); program.Run(); } public void Run() { Greeting.Say("Hello, World."); } } } /* 結果 Begin intercept... Hello, World. End intercept. */
一応は動いているみたいですが、Castle.DynamicProxyも見よう見まねで使ったので色々怪しそう・・・