我使用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
有没有解决方案?
提前致谢
答案 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,然后根据元数据对其进行过滤,以找到您想要的那个。