MEF初体验之八:过滤目录

时间:2023-01-21 20:41:44

当在使用子容器的时候,基于某些具体标准来过滤目录可能是重要的。例如,基于部件的创建策略来过滤是很常见的。下面的代码片段演示了如何构建这种特别方法:

var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var parent = new CompositionContainer(catalog); var filteredCat = new FilteredCatalog(catalog,
def => def.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) &&
((CreationPolicy)def.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) == CreationPolicy.NonShared);
var child = new CompositionContainer(filteredCat, parent); var root = child.GetExportedObject<Root>();
child.Dispose();

如果CreationPolicy还足以作为一个标准来选择部件的话,你或许想使用[PartMetadata]来代替。它允许你附加元数据在部件上,因此你可以使用它来构建一个过滤表达式。例如,下面是一个应用该特性的类:

[PartMetadata("scope", "webrequest"), Export]
public class HomeController : Controller
{
}

这使你可以用那些应该被限定到一个(逻辑)web请求的部件来创建子容器。注意它由你来定义一个范围边界,换句话说,MEF并不知道"webrequest"是什么,因此,你必须在每次web请求时建立一些基础设施代码来创建/释放容器。

var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var parent = new CompositionContainer(catalog); var filteredCat = new FilteredCatalog(catalog,
def => def.Metadata.ContainsKey("scope") &&
def.Metadata["scope"].ToString() == "webrequest");
var perRequest = new CompositionContainer(filteredCat, parent); var controller = perRequest.GetExportedObject<HomeController>();
perRequest.Dispose();

注意:我们没有提供FilteredCatalog类。下面我们将拿一个简单的实现来说明创建FilteredCatalog:

using System;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Linq.Expressions; public class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
{
private readonly ComposablePartCatalog _inner;
private readonly INotifyComposablePartCatalogChanged _innerNotifyChange;
private readonly IQueryable<ComposablePartDefinition> _partsQuery; public FilteredCatalog(ComposablePartCatalog inner,
Expression<Func<ComposablePartDefinition, bool>> expression)
{
_inner = inner;
_innerNotifyChange = inner as INotifyComposablePartCatalogChanged;
_partsQuery = inner.Parts.Where(expression);
} public override IQueryable<ComposablePartDefinition> Parts
{
get
{
return _partsQuery;
}
} public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed
{
add
{
if (_innerNotifyChange != null)
_innerNotifyChange.Changed += value;
}
remove
{
if (_innerNotifyChange != null)
_innerNotifyChange.Changed -= value;
}
} public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing
{
add
{
if (_innerNotifyChange != null)
_innerNotifyChange.Changing += value;
}
remove
{
if (_innerNotifyChange != null)
_innerNotifyChange.Changing -= value;
}
}
}

最后举个简单例子:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace FilteringCatalogsSample
{
class Program
{
[ImportMany]
public IEnumerable<IMessageSender> Senders { get; set; }
static void Main(string[] args)
{
Program p = new Program();
p.Compose();
foreach (var item in p.Senders)
{
item.Send("Hi,MEF");
}
Console.ReadKey();
}
void Compose()
{
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var parent = new CompositionContainer(catalog);
var filterCatalog = new FilteredCatalog(catalog,
def => def.Metadata.ContainsKey("methods")
&& def.Metadata["methods"].ToString() == "sms");
//var AggrContainer = new CompositionContainer(filterCatalog, parent);
var child = new CompositionContainer(filterCatalog);
child.ComposeParts(this);
}
}
interface IMessageSender
{
void Send(string msg);
}
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("Email sent:" + msg);
}
}
[Export(typeof(IMessageSender))]
public class SecureEmailSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("Secure Email sent:" + msg);
}
}
[Export(typeof(IMessageSender))]
[PartMetadata("methods","sms")]
public class SMSSender : IMessageSender
{
public void Send(string msg)
{
Console.WriteLine("SMS sent:" + msg);
}
}
}

输出如图:

MEF初体验之八:过滤目录