2009-12-04 11 views
20

Ich versuche seit einiger Zeit, Dinge mit MEF zu erledigen, aber jetzt stoße ich auf ein Problem, ich brauche Hilfe.Import-Eigenschaft immer Null (MEF-Import-Problem)

Beschreibung: Ich habe 2 DLL und eine EXE-Datei. ClassLibrary1 (LoggerImpl.cs, SomeClass.cs) ClassLibrary2 (ILogger.cs) WindowsApplicationForms1 (WindowsApplicaitonForms1.cs, Program.cs)

brauche ich Hilfe oder Richtung, warum dies nicht funktioniert?

// 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

Ihres 'SomeClass' ist nicht in der Zusammensetzung beteiligt, so werden seine Importe nie eingestellt werden. – dtb

Antwort

27

Wenn Sie eine neue Instanz einer Klasse selbst (neu Someclass()) erstellen, wobei der Behälter Ich werde nichts darüber wissen und werde es nicht komponieren.

Damit ein Teil von MEF erstellt wird, muss es von MEF erstellt oder explizit an den Container übergeben werden. Sie können manuell MEF sagen die Someclass Objekt Importe in der gleichen Art und Weise erfüllen Sie es gesagt, die Form der Einfuhr zu erfüllen:

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

Allerdings müssen Sie den direkten Zugriff auf den Behälter, dies zu tun, so dass es nicht funktioniert auch außerhalb Ihrer Form1-Klasse. Im Allgemeinen ist eine bessere Art und Weise, es zu tun wäre Someclass zu exportieren, und erstellen Sie einen Import in Ihrer Klasse Form1 für 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. Das Hauptproblem ist, dass die SomeClass selbst keinen Kompositionsbehälter hat. Wenn SomeClass selbst in eine Schnittstelle umgewandelt wurde, könnte ein IEnumerable (zum Beispiel) zusammen mit dem Attribut ImportMany verwendet werden, so dass es zu einer sehr einfachen Methode zum Hinzufügen von Teilen wird, indem Assemblys einfach ohne zusätzlichen Code in das Verzeichnis fallen gelassen werden. – JamesEggers

1

Sie brauchen eine Aussage wie ähnlich den folgenden, um die Someclass in der Zusammensetzung Prozess einzubeziehen

// 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

Danke für die Antwort. Also, wenn ich eine andere DLL mit Teilen hinzufügen, muss ich auch Client-Code ändern (lesen Sie Compose-Methode), um diese Teile zu enthalten? Ich dachte, dass, wenn ich ein anderes Teil erstellen und in ein Verzeichnis mit der App einlege, die Anwendung diese Teile verwenden kann, wenn die App selbst den passenden Import enthält (wie Meni, Logger, Toolbar usw.). – ITGoran

+2

In diesem Code erstellen Sie zwei separate Container, was wahrscheinlich nicht das ist, was Sie wollen. Mit zwei Containern erhalten Sie zwei separate Instanzen des Loggers in Ihrer Form1-Klasse und Ihrer SomeClass. –