MEF是微軟的一個ioc框架,使用非常方便,我們只需要在需要匯出的類上標記[Export],在需要使用的地方[import]就可以使用了。現在我們擴充套件MEF,在其裝配生成例項時,使用Castle DynamicProxy對其生成透明代理。
我們先實現一個攔截器,並且繼承Attribute基類,這個我們可以將這個攔截器作為類的特性來使用。
using Castle.DynamicProxy; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MefAopTest { public class LogInterceptor : Attribute,IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine("begin"); invocation.Proceed(); Console.WriteLine("end"); } } }
View Code
這個攔截器中,我們對攔截的方法執行前和執行後都增加了操作。
然後我們新增一個類,這個類使我們需要匯出的類。
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; namespace MefAopTest { [Export(typeof(ClassA))] [LogInterceptor] public class ClassA { public virtual void GetA() { Console.WriteLine("GetA"); } } }
View Code
在這個類上,我們增加特性 [Export(typeof(ClassA))],這是MEF的基本用法。[LogInterceptor]是我們定義的攔截器,我們可以攔截GetA方法。需要攔截的方法必須是虛方法。
下面我們來擴充套件下MEF。
ExportProvider 類:檢索與指定的 ImportDefinition 物件相匹配的匯出。這個類的作用很明確,就是用來尋找與 ImportDefinition 物件匹配的ExportDefinition。
我們新增一個基礎自ExportProvider 的類。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Composition.Hosting; using System.ComponentModel.Composition.Primitives; using Castle.DynamicProxy; namespace MefAopTest { public class AOPExportProvider : ExportProvider, IDisposable { private CatalogExportProvider _exportProvider; public AOPExportProvider(Func<ComposablePartCatalog> catalogResolver) { _exportProvider = new CatalogExportProvider(catalogResolver()); } public ExportProvider SourceProvider { get { return _exportProvider.SourceProvider; } set { _exportProvider.SourceProvider = value; } } protected override IEnumerable<Export> GetExportsCore( ImportDefinition definition, AtomicComposition atomicComposition) { IEnumerable<Export> exports = _exportProvider.GetExports(definition, atomicComposition); return exports.Select(export => new Export(export.Definition, () => GetValue(export))); } private object GetValue(Export innerExport) { object value = innerExport.Value; Type t = value.GetType(); IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray(); ProxyGenerator generator = new ProxyGenerator(); object proxy = generator.CreateClassProxy(value.GetType(), attribs); return proxy; } public void Dispose() { _exportProvider.Dispose(); } } }
在裝配時,會觸發GetExportsCore方法,去尋找相對應的匯出。我們在GetValue方法中,使用Castle生成動態代理。
IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();
上面這行程式碼主要是從需要匯出的類的自定義特性中,尋找攔截器。我們這裡定義的是[LogInterceptor]。
然後我們再生成透明的動態代理
ProxyGenerator generator = new ProxyGenerator(); object proxy = generator.CreateClassProxy(value.GetType(), attribs);
下面我們新增一個窗體類,窗體上有一個按鈕,點選按鈕,觸發ClassA例項的GetA方法。看是否可以進行攔截。
namespace MefAopTest { public : Form { public Form1() { InitializeComponent(); ComposeParts(); } [Import(typeof(ClassA))] private ClassA c1; public void ComposeParts() { Func<ComposablePartCatalog> catalogResolver = () => { var catalog = new AggregateCatalog(); AssemblyCatalog assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); catalog.Catalogs.Add(assemblyCatalog); return catalog; }; AOPExportProvider provider = new AOPExportProvider(catalogResolver); CompositionContainer container = new CompositionContainer(provider); provider.SourceProvider = container; container.ComposeParts(this); } private void Test_Click(object sender, EventArgs e) { c1.GetA(); } } }
在代理裡,我們定義了一個欄位,用來Import ClassA類。
[Import(typeof(ClassA))] private ClassA c1;
在我們裝配程式碼中,使用我們擴充套件的AopExportProvider
我們測試下,點選按鈕,看看輸出的情況。
好的,我們成功的攔截了ClassA的GetA方法,並在方法執行前和執行後都增加了操作。
這種AOP的實現,我們只需要在需要匯出的類上增加一個特性就行了。如果有其他需求,我們可以再增加攔截器,並在相應的類上增加特性就行了,很方便。美中不足的是,需要按照MEF的方式去生成例項,不能像postsharp那樣。