MEF属性始终返回null

3

原始源代码

我在我的BusinessObjects.dll文件中有一个简单的业务对象:

namespace BusinessObjects
{
    public class MyClass
    {
        public MyClass()
        {
            DateTime = DateTime.Now;
        }

        public DateTime DateTime { get; set; }
    }
}

在我的SharedUI.dll中,我有一个“上下文提供程序”类,用于保存对当前选择的MyClass的引用 - 请记住,这只是一个简化的示例 :)...

namespace SharedUI
{
    public class AppContext
    {
        [Export]
        public MyClass SelectedMyClass { get; private set; }

        public void SetupContext(MyClass myClass)
        {
            SelectedMyClass = myClass;
        }

        public static AppContext Context
        {
            get
            {
                if (context == null)
                {
                    context = new AppContext();
                }
                return context;
            }
        }

        private static AppContext context;
    }
}

我的 MefTest.exe 有这个类:

namespace MefTest
{
    public class Program
    {
        [Import]
        public MyClass MyClass { get; set; }

        private void Compose()
        {
            var ventSystem = new MyClass();
            AppContext.Context.SetupContext(ventSystem);

            var executingAssembly = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var contextAssembly = new AssemblyCatalog(Assembly.LoadFile(string.Format(@"{0}\SharedUI.dll", Environment.CurrentDirectory)));
            var catalog = new AggregateCatalog(executingAssembly, contextAssembly);

            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);
        }

        private void Run()
        {
            Compose();

            // MyClass is always null in the next line?
            Console.WriteLine(MyClass.DateTime.ToString());

            Console.ReadKey();
        }

        private static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }
    }
}

我是一个MEF新手,请多包涵 :)

根据Daniel Plaisted的建议更新源代码

MyClass源代码保持不变...

现在SharedUI.dll看起来是这样的:

namespace SharedUI
{
    [Export]
    public class AppContext
    {
        [Export(typeof(MyClass))]
        public MyClass SelectedMyClass { get; private set; }

        public void SetupContext(MyClass myClass)
        {
            SelectedMyClass = myClass;
        }
    }
}

MefTest.exe现在看起来像这样:

namespace MefTest
{
    public class Program
    {
        [Import]
        public MyClass MyClass { get; set; }

        [Import]
        public AppContext AppContext { get; set; }

        private void Compose()
        {
            var executingAssembly = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var contextAssembly = new AssemblyCatalog(Assembly.LoadFile(string.Format(@"{0}\SharedUI.dll", Environment.CurrentDirectory)));
            var catalog = new AggregateCatalog(executingAssembly, contextAssembly);

            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);

            var myClass = new MyClass();
            AppContext.SetupContext(myClass);
        }

        private void Run()
        {
            Compose();

            // AppContext.SelectedMyClass is NOT null in the next line... which is good I guess :)
            Console.WriteLine(AppContext.SelectedMyClass.DateTime.ToString());

            // MyClass is always null in the next line?
            Console.WriteLine(MyClass.DateTime.ToString());

            Console.ReadKey();
        }

        private static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }
    }
}

我做错了什么,导致它无法工作?

你已经验证它是否将“GUI”加载到AssemblyCatalog中了吗? - Jonas Van der Aa
@Jonas:你所说的“GUI”是指包含Program类、AppContext类或MyClass类的项目吗? - Kenneth Kryger Sørensen
抱歉,我混淆了两个不同的SO问题 :) 我指的是AppContext类。您是否已经验证它被MEF加载了? - Jonas Van der Aa
@Jonas:我想是这样。如果我从AppContext类中删除Export属性,container.ComposeParts(this)会抛出异常:“未找到与约束条件'((exportDefinition.ContractName ==“BusinessObjects.MyClass”)...匹配的有效导出项。” - Kenneth Kryger Sørensen
3个回答

2
当MEF需要获取一个在类属性上的Export时,它会创建该类的实例并调用属性getter。因此,MEF正在创建一个新的AppContext实例,与静态的AppContext.Context实例不同。MEF创建的实例没有设置SelectedMyClass属性,这就是为什么您的导入最终为空的原因。

我已经根据您的建议更新了原始问题 - 但是我无法使其工作?我在这里漏掉了什么? - Kenneth Kryger Sørensen
2
@kenneth,你修改后的示例有一个不同的问题。MEF只获取导出值一次,并且不知道它是否稍后更改。当您调用ComposeParts(this)时,它会提取MyClass导出的值。当您随后修改该属性时,它对导出值没有影响。 - Daniel Plaisted

1

问题是:

    [Import]        public MyClass MyClass { get; set; }

MyClass 没有定义 [Export]。MEF 将基于它“知道”的内容来组合此应用程序,因为它不知道“MyClass”...

我注意到了这个:

    [Export]        public MyClass SelectedMyClass { get; private set; }

这意味着您正在尝试欺骗MEF定期更新其部件?解决方案是创建一个包含“运行时”对象的自定义目录,其中您可以随时更新MyClass的导出值。当前实现永远不会解析MyClass...

[编辑:] 您也可以将成员装饰为Export,但必须在那里添加类类型。所以这将起作用:

[Export(typeof(MyClass)] public MyClass SelectedMyClass { get; private set; }


不幸的是,那似乎没有解决它 :( - Kenneth Kryger Sørensen

0

你把Export属性放错地方了。

你应该把它放在MyClass的定义上,像这样:

namespace BusinessObjects
{
[Export]
public class MyClass
{
    public MyClass()
    {
        DateTime = DateTime.Now;
    }

    public DateTime DateTime { get; set; }
}
}

然后在需要该类的实例的任何地方使用[Import]属性。

备注:您不能使用MEF移动类的特定实例(不像这样)。 MEF用于创建请求类型的实例并将它们注入指定位置。

要了解有关MEF的更多信息,请访问CodePlex项目页面。


如果我正确阅读文档链接,Export属性可以用于类、方法、属性和字段... 特别是备注部分的以下引用引起了我的兴趣: "ExportAttribute可以装饰整个类,也可以装饰类的属性、字段或方法。如果整个类被装饰,那么该类的实例就是导出对象。如果类的成员被装饰,则导出对象将是装饰成员的值。" - Kenneth Kryger Sørensen
1
尝试使用 [Export(typeof(MyClass))] 公共 MyClass SelectedMyClass { get; private set; } - maartenba
@maartenba:不幸的是,那似乎没有解决它 :( - Kenneth Kryger Sørensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接