MEF初体验之八:过滤目录

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

复制代码
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);
        }
    }
}
复制代码

输出如图:

posted @   jello chen  阅读(355)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报

点击右上角即可分享
微信分享提示