2009-06-22 132 views
5

我需要为我们现有的代码添加一些扩展点,我一直在寻找MEF作为可能的解决方案。我们有一个IRandomNumberGenerator接口,并有一个默认实现(ConcreteRNG),我们希望可以交换。这听起来像是MEF的理想场景,但是我们在实例化随机数生成器方面遇到了问题。我们当前的代码如下所示:我可以使用MEF控制对象的创建吗?

public class Consumer 
{ 
    private List<IRandomNumberGenerator> generators; 
    private List<double> seeds; 

    public Consumer() 
    { 
     generators = new List<IRandomNumberGenerator>(); 
     seeds = new List<double>(new[] {1.0, 2.0, 3.0}); 

     foreach(var seed in seeds) 
     { 
      generators.Add(new ConcreteRNG(seed)); 
     } 
    } 
} 

换句话说,消费者负责实例它所需要的随机数发生器,包括提供每个实例都需要种子。

我想要做的是让具体的RNG实现被MEF发现并实例化(使用DirectoryCatalog)。我不知道如何实现这一点。我可以公开一个Generators属性并将其标记为[Import],但是如何提供所需的种子?

有没有其他的方法我缺少?

回答

5

目前在MEF中没有直接的做法,但MEF团队正在考虑在v.Next中支持这一点。您基本上想要创建使用Factory模式传统完成的相同实现的多个实例。所以,你可以使用一个方法是这样的:

public interface IRandomNumberGeneratorFactory 
{ 
    IRandomNumberGenerator CreateGenerator(int seed); 
} 

[Export(typeof(IRandomNumberGeneratorFactory))] 
public class ConcreateRNGFactory : IRandomNumberGeneratorFactory 
{ 
    public IRandomNumberGenerator CreateGenerator(int seed) 
    { 
    return new ConcreateRNG(seed); 
    } 
} 

public class Consumer 
{ 
    [Import(typeof(IRandomNumberGeneratorFactory))] 
    private IRandomNumberGeneratorFactory generatorFactory; 
    private List<IRandomNumberGenerator> generators;  
    private List<double> seeds;  

    public Consumer()  
    { 
    generators = new List<IRandomNumberGenerator>(); 
    seeds = new List<double>(new[] {1.0, 2.0, 3.0}); 

    foreach(var seed in seeds) 
    {    
     generators.Add(generatorFactory.CreateGenerator(seed)); 
    } 
    } 
} 
+0

谢谢Wes。我曾考虑过一种工厂方法,但由于我想要一个通用工厂可以创建任何由MEF发现的IRandomNumberGenerator类型的实例,所以我陷入了困境。 再次思考它,你的方法似乎不再需要额外的工作 - 再次感谢。 – Akash 2009-06-23 08:05:17

+1

我现在正在工作。我在ConcreteRNG上提供了一个静态工厂方法来简化它: [Export(typeof(Func ))] public static readonly Func Create = seed => new ConcreteRNG(seed) ; – Akash 2009-06-23 13:48:29

+0

是导出一个函数本身也是另一种简化的方式来获得你想要的。我也意识到,如果你想在构造函数中使用该导入,那么你需要将它作为构造函数导入,因为我演示的导入不会在对象构造之前设置。 – 2009-06-25 16:29:44

0

我相信这是Lazy Exports的特点是什么。从这个页面:

[Import] 
public Export<IMessageSender> Sender { get; set; } 

在这种情况下,你是选择在了,直到你真正需要实现的实例延缓这个实例。为了请求实例,请使用方法[Export.GetExportedObject()]。请注意,此方法永远不会充当T实现的工厂,因此多次调用它将返回第一次调用时返回的相同对象实例。

4

MEF预览版8对此有实验支持,虽然它尚未包含在System.ComponentModel.Composition.dll中。有关更多信息,请参见this blog post

您必须下载MEF资源并构建解决方案。在Samples\DynamicInstantiation文件夹中,您可以找到程序集Microsoft.ComponentModel.Composition.DynamicInstantiation.dll。加入这个集的引用和动态实例提供程序添加到您的容器是这样的:

var catalog = new DirectoryCatalog("."); 
var dynamicInstantiationProvider = new DynamicInstantiationProvider(); 
var container = new CompositionContainer(catalog, dynamicInstantiationProvider); 
dynamicInstantiationProvider.SourceProvider = container; 

现在您的零件就能导入PartCreator<Foo>,如果他们需要动态地创建Foo部分。与编写自己的工厂类相比,它的优势在于它可以透明地处理Foo的进口以及进口的进口等等。

编辑

  • MEF Preview 9PartCreator更名为ExportFactory但它仅包含在Silverlight的版本。
  • in MEF 2 Preview 2ExportFactory已成为桌面版本。因此ExportFactory可能会成为.NET 4.0之后的下一个.NET框架版本的一部分。
相关问题