如何从MEF中的多个零件导入特定零件?

时间:2011-01-06 04:20:43

标签: mef

我使用MEF作为DI容器,问题是我想从多个部分导入特定部分。

例如,我有以下代码:

public interface IService
{
    void Send();
}

[Export(typeof(IService))]
public class Service : IService
{
    public void Send()
    {
        Console.WriteLine("Service.Send");
    }
}

[Export(typeof(IService))]
public class FakeService : IService
{
    public void Send()
    {
        Console.WriteLine("FakeService.Send");
    }
}

[Import]
public IService Service { get; set; } // ---> let's say I want to use FakeService

有没有解决方案?

提前致谢

3 个答案:

答案 0 :(得分:13)

您可以使用您的班级导出元数据,这是一个示例:

public interface ILogger
{
  void Log(string message);
}

[Export(typeof(ILogger)), ExportMetadata("Name", "Console")]
public class ConsoleLogger : ILogger
{
  public void Log(string message)
  {
    Console.WriteLine(message);
  }
}

[Export(typeof(ILogger)), ExportMetadata("Name", "Debug")]
public class DebugLogger : ILogger
{
  public void Log(string message)
  {
    Debug.Print(message);
  }
}

鉴于合同和那些示例实现,我们可以将类型导出为Lazy<T, TMetadata>,从而可以定义元数据合同:

public interface INamedMetadata
{
  string Name { get; }
}

您无需担心创建元数据的实现,因为MEF会将任何ExportMetadata属性值投影为TMetadata的具体实现,在我们的示例中为INamedMetadata 。有了上述内容,我可以创建以下示例:

public class Logger
{
  [ImportMany]
  public IEnumerable<Lazy<ILogger, INamedMetadata>> Loggers { get; set; }

  public void Log(string name, string message)
  {
    var logger = GetLogger(name);
    if (logger == null)
      throw new ArgumentException("No logger exists with name = " + name);

    logger.Log(message);
  }

  private ILogger GetLogger(string name)
  {
    return Loggers
      .Where(l => l.Metadata.Name.Equals(name))
      .Select(l => l.Value)
      .FirstOrDefault();
  }
}

在该示例类中,我将导入许多实例,作为Lazy<ILogger, INamedMetadata>个实例。使用Lazy<T,TMetadata>允许我们在访问值之前访问元数据。在上面的示例中,我使用name参数来选择要使用的适当记录器。

如果在导入时实例化类是不对的,可以使用ExportFactory<T,TMetadata>,它允许您根据需要启动类型的实例。 (ExportFactory包含在.NET 4.0的Silverlight版本中,但Glenn Block确实抛出了源代码on codeplex以供桌面/ Web使用。

我希望有所帮助。

答案 1 :(得分:3)

您也可以使用带有合同名称的Export重载。然后使用合同名称导入它。

[Export("Service", typeof(IService))]
public class Service : IService {
}

[Export("FakeService", typeof(IService))]
public class FakeService : IService {
}

[Import("FakeService")]
public IService Service { get; set; }

答案 2 :(得分:0)

您可以添加导出元数据以区分不同的导出。然后在导入方面,您将需要使用ImportMany,然后根据元数据对其进行过滤,以找到您想要的那个。