2009-12-04 16 views
20

Intento por algún tiempo hacer las cosas usando MEF pero ahora, me encuentro con un problema y necesito ayuda.Importar propiedad siempre nula (problema de importación de MEF)

Descripción: Tengo 2 DLL y un archivo EXE. ClassLibrary1 (LoggerImpl.cs, SomeClass.cs) ClassLibrary2 (ILogger.cs) WindowsApplicationForms1 (WindowsApplicaitonForms1.cs, Program.cs)

que necesitan ayuda o dirección por qué esto no funciona?

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

Su 'SomeClass' no está involucrado en la composición, por lo que nunca se establecerán sus importaciones. – dtb

Respuesta

27

Si crea una nueva instancia de una clase a sí mismo (nuevo SomeClass()), el contenedor no sabrá nada al respecto y no lo compondrá.

Para que una parte sea compuesta por MEF, debe ser creada por MEF, o pasada explícitamente al contenedor. Se puede decir manualmente MEF para satisfacer las importaciones del objeto SomeClass de la misma manera que le dijo que para satisfacer las importaciones de la forma:

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

Sin embargo, se necesita acceso directo al recipiente para ello, por lo que no funciona también fuera de su clase Form1. En general, una mejor manera de hacerlo sería para exportar SomeClass, y crear una importación en su clase Form1 para 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. El problema principal es que SomeClass no tiene un contenedor de composición en sí mismo. Si SomeClass se convirtió en una interfaz, se podría usar un IEnumerable (por ejemplo) junto con el atributo ImportMany para que se convierta en una forma muy simple de agregar partes simplemente colocando ensamblados en el directorio sin código adicional. – JamesEggers

1

Se necesita una declaración como similar al siguiente para involucrar a la SomeClass en el proceso de composición

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

Gracias por su respuesta. Entonces, si agrego otra DLL con partes, ¿también debo cambiar el código del cliente (leer el método Compose) para incluir esas partes? Estaba pensando que si creo otra Parte y la pongo en el directorio con la aplicación, la aplicación puede usar esas partes si la aplicación contiene la Importación apropiada (como, Meni, Logger, Barra de herramientas, etc.). – ITGoran

+2

En este código está creando dos contenedores separados, que probablemente no es lo que desea. Con dos contenedores, obtendría dos instancias separadas del registrador en su clase Form1 y su SomeClass. –

Cuestiones relacionadas