2009-12-04 31 views
20

我尝试了一段时间使用MEF完成任务,但现在遇到了问题,我需要帮助。导入属性始终为空(MEF导入问题)

描述: 我有2个DLL和一个EXE文件。 ClassLibrary1的(LoggerImpl.cs,SomeClass.cs) ClassLibrary2(ILogger.cs) WindowsApplicationForms1(WindowsApplicaitonForms1.cs,Program.cs中)

我需要任何帮助或指导为什么不起作用?

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

你'SomeClass'不参与组成,因此它的进口量将永远不会被设置。 – dtb

回答

27

(新SomeClass的()),容器将不知道任何关于它,并不会构成它。

对于由MEF组成的部分,它需要由MEF创建,或者明确传递给容器。您可以手动告诉MEF以满足相同的方式SomeClass的对象的进口,你告诉它满足形式进口:

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

但是,你需要的容器要做到这一点直接访问,因此它不工作以及您的Form1类以外。在一般情况下,一个更好的方式做这将是你的Form1类出口SomeClass的,并创建一个导入为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。主要问题是SomeClass本身没有组合容器。如果SomeClass自己变成了一个接口,IEnumerable (例如)可以与ImportMany属性一起使用,这样它就变成了一种非常简单的添加部件的方法,只需将程序集放到没有附加代码的目录中即可。 – JamesEggers

1

你需要像类似的声明,下面如果你创建一个类自己的新实例到SomeClass的参与,组成过程

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

感谢您的回复。 因此,如果我添加其他DLL的部分,我也必须更改客户端代码(阅读撰写方法),以包括这些部分? 我在想,如果我创建另一个部件并将其放入应用程序目录,应用程序可以使用该部件,如果应用程序本身包含适当的导入(如,Meni,Logger,Toolbar等)。 – ITGoran

+2

在此代码中,您正在创建两个单独的容器,这可能不是您想要的。使用两个容器,您将在Form1类和SomeClass中获得两个单独的记录器实例。 –