使用MEF创建的参数创建类的实例

时间:2012-04-15 14:20:03

标签: .net mef composition

我有以下情况。在程序集A中,我有以下内容:

public class Service : IService
{
   private readonly IDependency dependency;

   public Service(IDependency dependency)
   {
       this.dependency = dependency;
   }
}

在程序集B和C中,我有IDependency的不同实现:

[Export(typeof(IDependency)]
public class Dependency1 : IDependency { }

[Export(typeof(IDependency)]
public class Dependency2 : IDependency { }

如何指示MEF为每个导出的Service创建IDependencies的实例?

2 个答案:

答案 0 :(得分:2)

MEF不支持开箱即用。您有两种选择:

  1. 据推测,您计划在某个地方执行[ImportMany(typeof(IService))]导入所有服务实例。相反,您可以导入如下所示的ServiceProvider对象:

    [Export]
    public class ServiceProvider
    {
        [ImportMany]
        public IEnumerable<IDependency> Dependencies { get; set; }
    
        public IEnumerable<IService> GetServices()
        {
           return Dependencies.Select(x => new Service(x));
        }
    }
    
  2. 您可以使用自己的导出提供程序实现来扩充MEF。我已经玩弄了添加[ExportMany]属性的想法,该属性可以被这样的自定义导出提供程序识别。它似乎工作,但它只是一个概念的证明。请参阅https://bitbucket.org/wcoenen/mefexportmany/

答案 1 :(得分:1)

正如Wim所说,这不是开箱即用的原生支持。如果你想做这样的事情:

[ImportMany]
public IEnumerable<Service> _services { get; set; }

...没有使用工厂(例如Wim详述的ServiceProvider),那么出口提供商就可以工作,例如:

public class ServiceExportProvider : ExportProvider
{
  private const string ContractName = AttributedModelServices.GetContractName(typeof(Service));

  public ExportProvider SourceProvider { get; set; }

  protected override IEnumerable<Export> GetExportsCore(ImportDefinition def, AtomicComposition ac)
  {
    if (SourceProvider == null)
      throw new InvalidOperationException("SourceProvider property must be set.");

    if (def.ContractName.Equals(ContractName))
    {
      return SourceProvider
        .GetExports<IDependency>()
        .Select(e => new Export(def.ContractName, () => new Service(e.Value)));
    }

    return Enumerable.Empty<Export>();
  }
}

您不需要[Export] Service类型(实际上可能会导致问题),但[Import][ImportMany] Service如果您已使用容器向提供者注册,则设置SourceProvider属性:

var catalog = // create catalogs/
var provider = new ServiceExportProvider();
var container = new CompositionContainer(catalog, provider);
provider.SourceProvider = container;