2010-09-24 7 views
5

Próbuję przekonwertować MEF, aby ponownie skompilował wszystkie części, o których wie, kiedy aktualizuję wyeksportowaną instancję. Zasadniczo chcę mieć MEF aktualizacji wszystkie moje części, które importują wartość konfiguracyjną ciąg połączenia, gdy jest zmieniany. Wszystko wygląda dobrze aż do momentu, w którym chcę zmienić instancję. Jeśli spróbuję utworzyć ComposeParts z zaktualizowaną wartością, wydaje się, że dodaję drugą część instancji do kontenera, a następnie mój import jest aktualizowany, ale ma wartość NULL.Jak mogę przekonwertować MEF podczas zmiany części?

Czy ktoś może wskazać, gdzie się źle wybieram? A może powinienem próbować używać MEF w ten sposób?

Używam podglądu MEF 9 i targetting .net framework 3.5 i WPF.

using System; 
using System.Collections.Generic; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.Linq; 
using System.Text; 
using Shouldly; 

namespace ConsoleApplication4 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MainClass main = new MainClass(); 
      main.RunTest(); 
     } 
    } 

    public class MainClass 
    { 
     [ImportMany] 
     public IEnumerable<Settings> Settings { get; set; } 

     public void RunTest() 
     { 
      AggregateCatalog catalog = new AggregateCatalog(); 
      catalog.Catalogs.Add(new AssemblyCatalog(typeof(Settings).Assembly)); 

      CompositionContainer container = new CompositionContainer(catalog); 

      container.SatisfyImportsOnce(this); 

      Config cfg = new Config 
      { 
       Settings = new Settings { ConnectionString = "Value1" }, 
      }; 

      // result is returned with a null settings value 
      UsesSettings result = container.GetExportedValue<UsesSettings>(); 

      // this recomposes everything with the new value, result changes to have settings of Value1 
      container.ComposeParts(cfg); 

      // this line results in my import many enumerable returning 2 parts the Value1 setting and null 
      container.SatisfyImportsOnce(this); 

      result.TheSettings.ConnectionString.ShouldBe("Value1"); 

      cfg.Settings = new Settings { ConnectionString = "Value2" }; 

      // how do I tell the container to recompose now I have changed the config object, 
      // or how do I replace the part value with the new value? 

      // this line causes the result.Settings to return null 
      container.ComposeParts(cfg); 

      // this updates the ImportMany to 3 values, Value1, Value2 and null 
      container.SatisfyImportsOnce(this); 
     } 
    } 

    public class Settings 
    { 
     public string ConnectionString = "default value"; 
    } 

    public class Config 
    { 
     [Export(typeof(Settings))] 
     public Settings Settings { get; set; } 
    } 

    [Export(typeof(UsesSettings))] 
    public class UsesSettings 
    { 
     [Import(typeof(Settings), AllowRecomposition = true)] 
     public Settings TheSettings { get; set; } 
    } 
} 

Odpowiedz

6

Masz kilka drobiazgów dla scenariusza, który próbujesz osiągnąć.

Po pierwsze: jeśli chcesz dodać/usunąć/zmienić określony wywóz, nie może on znajdować się w samym katalogu, dlatego powinieneś usunąć swoją klasę Config, która ma właściwość Eksportuj ustawienia. Jest to tworzone przez narzędzie CatalogExportProvider i jest powodem, dla którego widzisz wartość pustą w kolekcji.

Spróbuj wykonać następujące czynności:

public class Program 
{ 
    [ImportMany(AllowRecomposition=true)] 
    public IEnumerable<Settings> Settings { get; set; } 

    public void RunTest() 
    { 
     AggregateCatalog catalog = new AggregateCatalog(); 
     catalog.Catalogs.Add(new AssemblyCatalog(typeof(Settings).Assembly)); 

     CompositionContainer container = new CompositionContainer(catalog); 

     // Settings should have 0 values. 
     container.ComposeParts(this); 
     Contract.Assert(this.Settings.Count() == 0); 

     CompositionBatch batch = new CompositionBatch(); 

     // Store the settingsPart for later removal... 
     ComposablePart settingsPart = 
      batch.AddExportedValue(new Settings { ConnectionString = "Value1" }); 

     container.Compose(batch); 

     // Settings should have "Value1" 
     UsesSettings result = container.GetExportedValue<UsesSettings>(); 
     Contract.Assert(result.TheSettings.ConnectionString == "Value1"); 

     // Settings should have 1 value which is "Value1"; 
     Contract.Assert(this.Settings.Count() == 1); 
     Contract.Assert(this.Settings.First().ConnectionString == "Value1"); 

     // Remove the old settings and replace it with a new one. 
     batch = new CompositionBatch(); 
     batch.RemovePart(settingsPart); 
     batch.AddExportedValue(new Settings { ConnectionString = "Value2" }); 
     container.Compose(batch); 

     // result.Settings should have "Value2" now. 
     Contract.Assert(result.TheSettings.ConnectionString == "Value2"); 

     // Settings should have 1 value which is "Value2" 
     Contract.Assert(this.Settings.Count() == 1); 
     Contract.Assert(this.Settings.First().ConnectionString == "Value2"); 
    } 
} 
public class Settings 
{ 
    public string ConnectionString = "default value"; 
} 

[Export(typeof(UsesSettings))] 
public class UsesSettings 
{ 
    [Import(typeof(Settings), AllowRecomposition = true)] 
    public Settings TheSettings { get; set; } 
} 
+0

Dzięki Wes! Zmieniłem swój kod, by trzymać się części składowej, która pozwoliła mi zaktualizować część w kontenerze, zamiast dodawać coraz więcej instancji, teraz działa świetnie. – Matt

Powiązane problemy