How to import specific part from multi parts in MEF?

自闭症网瘾萝莉.ら 提交于 2019-12-04 12:18:30

问题


I am using MEF as DI container and the problem is that I want to import specific part from multiple parts.

For example, I have following codes :

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

Is there any solution?

Thanks in advance


回答1:


You can export metadata with your class, here's an example:

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);
  }
}

Given that contract and those example implementations, we can import out types as Lazy<T, TMetadata> whereby we can define a metadata contract:

public interface INamedMetadata
{
  string Name { get; }
}

You don't need to worry about creating an implementation of the metadata, as MEF will project any ExportMetadata attribute values as concrete implementation of TMetadata, which in our example is INamedMetadata. With the above, I can create the following example:

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();
  }
}

In that sample class, I am importing many instances, as Lazy<ILogger, INamedMetadata> instances. Using Lazy<T,TMetadata> allows us to access the metadata before accessing the value. In the example above, I'm using the name argument to select the appropriate logger to use.

If it is not right to instantiate the class on import, you can use an ExportFactory<T,TMetadata> which allows you to spin up instances of your types on demand. (ExportFactory is included in the Silverlight version of .NET 4.0, but Glenn Block did throw the source code on codeplex for Desktop/Web use.

I hope that helps.




回答2:


You can use the overload of Export that takes a contract name as well. Then import it with the contract name.

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

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

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



回答3:


You can add export metadata to distinguish the different exports from each other. Then on the import side you will need to use an ImportMany and then filter it based on the metadata to find the one you want.



来源:https://stackoverflow.com/questions/4611706/how-to-import-specific-part-from-multi-parts-in-mef

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!