【问题标题】:Exception when using MEF compose parts使用 MEF 组合部件时出现异常
【发布时间】:2012-11-05 08:38:34
【问题描述】:

我正在尝试了解 MEF 并对此做了一些示例。但是,当我尝试执行下面的特定代码时,我遇到了一个例外。

ConsoleApplication2.program

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespace ConsoleApplication2
{
    class Program 
    {
     [Import(typeof(Contracts.IInput))]
     public Contracts.IInput myinterface { get; set; }

    public void Method()
    {
        var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);
        container.ComposeParts(container );
        Console.WriteLine(myinterface.IsValid());
    }

    public static void Main(string[] args)
    {
        var obj = new Program();
        obj.Method();
        Console.ReadLine();
    }

   }
}

我有一个单独的项目来定义接口。

namespace Contracts
{
   public interface IInput
    {
      //All classes that inherit IInput must implement the IsValid Property.
      string IsValid();
    }
}

在另一个单独的项目中,我使用了一个导出类。

 using System.ComponentModel.Composition;
 using Contracts;

 namespace Plugin
 {
    [Export(typeof(Contracts.IInput))]
    public class Plugin : IInput
    {
        public string IsValid()
        {
             return "1";
        }
    }
 }

现在,所有这些都在同一个“bin\Debug”文件夹中生成(两个库文件和一个可执行文件)。但是在到达代码时执行,“composeParts(this)”出现如下异常,

Object reference not set to an instance of an object.

当我尝试更改“Composeparts(container)”时,出现另一个异常,如下所示,

**> 合成产生了单个合成错误。根本原因是

提供如下。查看 CompositionException.Errors 属性 更详细的信息。

1) 无法填充集合 'ConsoleApplication2.Program.myinterface' 因为它没有 实现 ICollection 或者是只读的。如果集合不是 IEnumerable 或 T[] 它必须实现 ICollection 并且是 使用默认构造函数预初始化或可写。

导致:无法激活部件“ConsoleApplication2.Program” 元素:ConsoleApplication2.Program --> ConsoleApplication2.Program **

  1. 你能告诉我哪里出错了吗?
  2. 我认为 composeparts(this) 和 composeparts(container) 都是相同的,因为我使用的是 Assembly.GetExecutingAssembly()。如果是这样,那为什么会抛出两个不同的异常?

我用过 importmany 之类的

class Program 
 {
    [ImportMany(typeof(Contracts.IInput))]
    public IEnumerable<Contracts.IInput> myinterface { get; set; }

    public void Method()
    {
        var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);

        try
        {
            container.ComposeParts(container);
            foreach (var i in myinterface)
                Console.WriteLine(i.IsValid());
        }
        catch (CompositionException compositionException)
        {

            Console.WriteLine(compositionException.ToString());
        }



    }

但在这种情况下,myinterface 仍然为 null,这会引发 null 引用异常。

【问题讨论】:

  • 按照 Blachshma 的方式,只需将 assemblycatalog 更改为 DirectoryCatalog,这个例子就可以了!
  • 感谢 Blachshma 的额外回答。如果我对他的理解正确,那么这些就是这里的要点: 1. import 语句只有在 Constructor 完成运行后才会发挥作用。 2. 所以不要对构造函数中的属性使用 import 语句。希望这可以帮助。 3. 目录目录在指定目录中查找满足import语句的dll。 4. 此外,程序集目录在可执行文件的项目中搜索满足导入语句的任何类/属性。

标签: c# visual-studio-2010 .net-4.0 mef


【解决方案1】:

有2个问题:

首先: 使用Import 而不是ImportMany

因为ImportMany 需要一个集合,所以你应该使用这样的东西:

public IEnumerable&lt;Contracts.IInput&gt; myinterface { get; set; }

第二:

正如您不能在构造函数中使用具有Import 属性的属性(这就是importing constructor 的用途),您也不能在程序的Main 函数中访问它们。

例如,这将起作用:

var catalog = new AggregateCatalog();
//Add all the parts found in all assemblies in
//the same directory as the executing program

catalog.Catalogs.Add(
                new DirectoryCatalog(
                    Path.GetDirectoryName(
                    Assembly.GetExecutingAssembly().Location
                    )
                )
            );

var container = new CompositionContainer(catalog);
container.ComposeParts(container);

// Use the container to get a value for myinterface
myinterface = container.GetExportedValue<Contracts.IInput>();
Console.WriteLine(myinterface.IsValid());

【讨论】:

  • 谢谢布拉赫什玛。我试过进口。但我仍然得到同样的例外。
  • 是的,我在使用导入时遇到了这个错误。但是现在我按照您的建议将以下代码与 importmany 一起使用。 [ImportMany(typeof(Contracts.IInput))] public IEnumerable myinterface { get;放; } public void Method() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog);尝试 { container.ComposeParts(container); foreach (var i in myinterface) Console.WriteLine(i.IsValid()); }
  • 当我使用上面的代码时,它抛出了一个空引用异常。 “我的界面”为空..
  • 我无法阅读代码,请在您的问题中发布。 另外您要加载到目录的程序集是带有导出的程序集而不是带有导入的程序集
  • 我所有的程序集都在 bin\Debug 文件夹中。我手动检查了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 2011-03-04
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
相关资源
最近更新 更多