2009-12-04 4 views
20

J'essaye depuis un certain temps de faire des choses en utilisant MEF mais maintenant, je rencontre un problème j'ai besoin d'aide.Importer la propriété toujours NULL (problème d'importation MEF)

Description: J'ai 2 DLL et un fichier EXE. ClassLibrary1 (LoggerImpl.cs, SomeClass.cs) ClassLibrary2 (ILogger.cs) WindowsApplicationForms1 (WindowsApplicaitonForms1.cs, Program.cs)

je besoin d'aide ou direction pourquoi cela ne fonctionne pas?

// ClassLibrary1.dll 
//SomeClass.cs 
public class SomeClass 
    { 
     [Import("Logging", typeof(ILogger))] 
     public ILogger Log { get; set; } <-- ALWAYS NULL ??? 

     public void Print() 
     { 
      Log.Print(); 
     } 

    } 

// ClassLibrary1.dll 
// LoggerImpl.cs 
namespace ClassLibrary1 
{ 
    [Export("Logging", typeof (ILogger))] 
    public class LoggerImpl : ILogger 
    { 
     public void Print() 
     { 
      Console.WriteLine("print called"); 
     } 
    } 
} 

// ClassLibrary2.dll 
// ILogger.cs 
namespace LogNamespace 
{ 
    public interface ILogger 
    { 
     void Print(); 
    } 
} 

// WindowsFormsApplication1.exe 
// WindowsFormsApplication1.cs 
namespace WindowsFormsApplication1 
{ 
    [Export("Form1",typeof(Form1))] 
    public partial class Form1 : Form 
    { 

     [Import("Logging", typeof(ILogger))] 
     public ILogger Log { set; get; } 

     private CompositionContainer _container; 

     public Form1() 
     { 
      InitializeComponent(); 
      Compose(); 
      Log.Print(); 

      SomeClass c = new SomeClass(); 
      c.Print(); 
     } 

     private void Compose() 
     { 
      var catalog = new AggregateCatalog(); 

      catalog.Catalogs.Add(new DirectoryCatalog(".")); 
      catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); 
      _container = new CompositionContainer(catalog); 

      try 
      { 
       _container.ComposeParts(this); 
      } 
      catch (CompositionException compositionException) 
      { 
       MessageBox.Show(compositionException.ToString()); 
      } 
     } 
    } 
} 
+2

Votre 'SomeClass' ne participe pas à la composition, de sorte que ses importations ne seront jamais réglées. – dtb

Répondre

27

Si vous créez une nouvelle instance d'une classe vous (nouvelle SomeClass()), le récipient ne saura rien et ne le composera pas.

Pour qu'une pièce soit composée par MEF, elle doit être créée par MEF ou transmise explicitement au conteneur. Vous pouvez manuellement dire MEF pour satisfaire les importations objet SomeClass de la même manière que vous avez dit à satisfaire les importations du formulaire:

SomeClass c = new SomeClass(); 
_container.SatisfyImports(c); 
c.Print(); 

Cependant, vous avez besoin d'un accès direct au conteneur pour ce faire, il ne fonctionne pas aussi bien en dehors de votre classe Form1. En général, une meilleure façon de le faire serait d'exporter SomeClass et créer une importation dans votre classe Form1 pour SomeClass:

[Export] 
public class SomeClass 
{ 
    [Import("Logging", typeof(ILogger))] 
    public ILogger Log { get; set; } 

    // etc. 
} 

public partial class Form1 : Form 
{ 
    [Import("Logging", typeof(ILogger))] 
    public ILogger Log { set; get; } 

    [Import] 
    SomeClass _someClass { get; set; } 

    // etc. 
} 
+0

+1. Le problème principal est que SomeClass n'a pas de conteneur de composition lui-même. Si SomeClass a été transformée en une interface elle-même, un IEnumerable (par exemple) pourrait être utilisé avec l'attribut ImportMany afin qu'il devienne un moyen très simple d'ajouter des parties en déposant simplement des assemblys dans le répertoire sans code supplémentaire. – JamesEggers

1

Vous avez besoin d'une déclaration comme similaire à ce qui suit pour impliquer le SomeClass dans le processus de composition

// ClassLibrary1.dll 
//SomeClass.cs 
using System; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.Windows.Forms; 
using LogNamespace; 

public class SomeClass 
{ 
    [Import("Logging", typeof(ILogger))] 
    public ILogger Log { get; set; } //<-- ALWAYS NULL ??? 

    public SomeClass() 
    { 
     var catalog = new AggregateCatalog(); 
     CompositionContainer _container; 

     // catalog.Catalogs.Add(new DirectoryCatalog(".")); 
     catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); 
     _container = new CompositionContainer(catalog); 

     _container.ComposeParts(this); 
    } 

    public void Print() 
    { 
     Log.Print(); 
    } 

} 

// ClassLibrary1.dll 
// LoggerImpl.cs 
namespace ClassLibrary1 
{ 
    [Export("Logging", typeof(ILogger))] 
    public class LoggerImpl : ILogger 
    { 
     public void Print() 
     { 
      Console.WriteLine("print called"); 
     } 
    } 
} 

// ClassLibrary2.dll 
// ILogger.cs 
namespace LogNamespace 
{ 
    public interface ILogger 
    { 
     void Print(); 
    } 
} 

// WindowsFormsApplication1.exe 
// WindowsFormsApplication1.cs 
namespace WindowsFormsApplication1 
{ 
    [Export("Form1", typeof(Form1))] 
    public partial class Form1 : Form 
    { 

     [Import("Logging", typeof(ILogger))] 
     public ILogger Log { set; get; } 

     private CompositionContainer _container; 

     public Form1() 
     { 
      InitializeComponent(); 
      Compose(); 
      Log.Print(); 

      SomeClass c = new SomeClass(); 
      c.Print(); 
     } 

     private void Compose() 
     { 
      var catalog = new AggregateCatalog(); 

      // catalog.Catalogs.Add(new DirectoryCatalog(".")); 
      catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); 
      _container = new CompositionContainer(catalog); 

      try 
      { 
       _container.ComposeParts(this); 
      } 
      catch (CompositionException compositionException) 
      { 
       MessageBox.Show(compositionException.ToString()); 
      } 
     } 
    } 
} 
+0

Merci pour la réponse. Donc, si j'ajoute une autre DLL avec des parties, je dois aussi changer le code client (lire la méthode Compose) pour inclure ces parties? Je pensais que si je crée une autre partie et mettre dans le répertoire avec l'application, l'application peut utiliser ces parties si l'application elle-même contient Import approprié (comme, Meni, Logger, barre d'outils, etc.). – ITGoran

+2

Dans ce code, vous créez deux conteneurs distincts, ce qui n'est probablement pas ce que vous voulez. Avec deux conteneurs, vous obtiendrez deux instances distinctes de l'enregistreur dans votre classe Form1 et votre SomeClass. –

Questions connexes