2009-06-22 79 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框架版本的一部分。
相關問題