我使用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
Run Code Online (Sandbox Code Playgroud)
有什么解决方案吗?
提前致谢
Mat*_*ott 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);
}
}
Run Code Online (Sandbox Code Playgroud)
鉴于合同和那些示例实现,我们可以导出类型,Lazy<T, TMetadata>以便我们可以定义元数据合同:
public interface INamedMetadata
{
string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)
您不必担心创建元数据的实现,因为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();
}
}
Run Code Online (Sandbox Code Playgroud)
在该示例类中,我将导入许多实例作为Lazy<ILogger, INamedMetadata>实例.使用Lazy<T,TMetadata>允许我们在访问值之前访问元数据.在上面的示例中,我使用name参数来选择要使用的适当记录器.
如果在导入时实例化类是不对的,您可以使用一个ExportFactory<T,TMetadata>允许您根据需要启动类型实例的方法.(ExportFactory包含在.NET 4.0的Silverlight版本中,但Glenn Block确实将源代码放在codeplex上以供桌面/ Web使用.
我希望有所帮助.