MEF是微軟的一個ioc框架,使用非常方便酥泞,我們只需要在需要導出的類上標記[Export]育特,在需要使用的地方[import]就可以使用了。現(xiàn)在我們擴展MEF疫萤,在其裝配生成實例時颂跨,使用Castle DynamicProxy對其生成透明代理。
我們先實現(xiàn)一個攔截器扯饶,并且繼承Attribute基類恒削,這個我們可以將這個攔截器作為類的特性來使用。
<pre>
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");
}
}
}
</pre>
這個攔截器中尾序,我們對攔截的方法執(zhí)行前和執(zhí)行后都增加了操作钓丰。
然后我們新增一個類,這個類使我們需要導出的類每币。
<pre>
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");
}
}
}
</pre>
在這個類上携丁,我們增加特性 [Export(typeof(ClassA))],這是MEF的基本用法兰怠。[LogInterceptor]是我們定義的攔截器梦鉴,我們可以攔截GetA方法。需要攔截的方法必須是虛方法揭保。
下面我們來擴展下MEF肥橙。
ExportProvider 類:檢索與指定的 ImportDefinition 對象相匹配的導出。這個類的作用很明確秸侣,就是用來尋找與 ImportDefinition 對象匹配的ExportDefinition存筏。
我們新增一個基礎自ExportProvider 的類。
<pre>
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();
}
}
}
</pre>
在裝配時味榛,會觸發(fā)GetExportsCore方法京郑,去尋找相對應的導出洋魂。我們在GetValue方法中,使用Castle生成動態(tài)代理。
<pre>
IInterceptor[] attribs = t.GetCustomAttributes(typeof(IInterceptor), true).Cast<IInterceptor>().ToArray();
</pre>
上面這行代碼主要是從需要導出的類的自定義特性中关翎,尋找攔截器变泄。我們這里定義的是[LogInterceptor]亮元。
然后我們再生成透明的動態(tài)代理
<pre>
ProxyGenerator generator = new ProxyGenerator();
object proxy = generator.CreateClassProxy(value.GetType(), attribs);
</pre>
下面我們新增一個窗體類袖外,窗體上有一個按鈕,點擊按鈕略吨,觸發(fā)ClassA實例的GetA方法集币。看是否可以進行攔截翠忠。
<pre>
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();
}
}
}
</pre>
在代理里鞠苟,我們定義了一個字段,用來Import ClassA類。
<pre>
[Import(typeof(ClassA))]
private ClassA c1;
</pre>
在我們裝配代碼中当娱,使用我們擴展的AopExportProvider
我們測試下吃既,點擊按鈕,看看輸出的情況跨细。
好的鹦倚,我們成功的攔截了ClassA的GetA方法,并在方法執(zhí)行前和執(zhí)行后都增加了操作冀惭。
這種AOP的實現(xiàn)震叙,我們只需要在需要導出的類上增加一個特性就行了。如果有其他需求散休,我們可以再增加攔截器媒楼,并在相應的類上增加特性就行了,很方便戚丸。美中不足的是划址,需要按照MEF的方式去生成實例,不能像postsharp那樣限府。