如何从MEF导入中创建新对象

4

我对MEF有点困惑,以为已经开始理解了,但似乎还没有完全掌握。

所以,我有一个XML测试步骤列表需要读取。想法是主应用程序在运行时不知道任何类型信息。

<TestSteps>
    <TestRunner xsi:type="SimulateDc" Measurement="54"/>
    <TestRunner xsi:type="MeasureDc" Output="1"/>
</TestSteps>

所以我有一个基础类型,其中包含一个静态的“results”类,允许我保存信息以在步骤之间传递(上面XML中的Output属性)。这里的测试处理程序由MEF导出,我在运行时读取它们,然后获取Type以传递到XML序列化器以创建处理程序列表。这一切都有效,并且我得到了一个测试运行程序列表。我为每种类型都有一个DataTemplate导出,因此当我使用内容控件时,它知道如何绘制自己。一切似乎都很好,但是我认为我的思路有误。

其中一个问题是我现在想将导入的处理程序与某些硬件绑定。硬件处理例程打算由更多的MEF导入来处理。

因此,具有以下接口:

public interface IMeasureHW
{
    double Measure();
}

然后使用这个:
[Export("MeasureDc", typeof(IMeasureHW))]
public class MeasureDcHW : IMeasureHW
{
    public double Measure()
    {
        return 54.0;
    }
}

然后,在我的一个测试处理程序中,我做了这个:

[Import("MeasureDc", typeof(IMeasureHW))]
IMeasureHW hardware { get; set; }

我的导入方式如下:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    var catalog = new AggregateCatalog();
    catalog.Catalogs.Add(new DirectoryCatalog("."));
    catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

    _container = new CompositionContainer(catalog);

    _container.ComposeParts(this);

    MainWindow.Show();
}

然而,我猜测上面的XML序列化并像我这样使用Type信息肯定意味着导入将为空,因此暗示我的设计思路是错误的。

我设法通过导出CompositionContainer并在加载XML后执行以下操作使其正常工作:

foreach (TestRunnerBase t in testSteps)
{
    _container.SatisfyImportsOnce(t);
}

但是我觉得这有些不对,因为导入的测试步骤初始列表除了获取类型外并没有被用于其他任何目的。所以我想我应该将数据作为MEF部件导出,然后独立地导出处理程序,然后在从XML中读取数据的时候,我可以从列表中请求处理程序?如果这有意义的话?

我无法弄清楚如何以这种方式将它们联系在一起,因为MEF组合都是在我的App.xaml.cs中处理的,而测试步骤则在其他地方的视图模型中。我正在考虑使用元数据来将数据与处理程序绑定,然后在导入的列表中找到相应的处理程序。也许我应该进行初始解析以建立字典来加速查找?

这是更应该这样做的方式吗?任何帮助都将不胜感激,我已经很轻微的脱发了,所以我负担不起再失去更多了。


1
你是否通过MEF容器创建测试处理程序?你能否发布执行容器和目录创建的代码? - Dennis
事实证明,我犯了一些错误,最初的导入并不为空。因此,我已经相应地更新了问题,因为它实际上与我所想的不同。 - Firedragon
你看过MEF的导出元数据吗?http://mef.codeplex.com/wikipage?title=Exports%20and%20Metadata - Panos Rontogiannis
1个回答

0

如果我错了,请纠正我 - 看起来您可以通过链接导入来实现您的目标:最内层是您的TestRunner集合,然后是硬件类,最后是内容控制。

在下面的示例中,它们分别是Class2 : MySubInterfaceClass1 : MyInterfaceProgram

/////inner

using MyHostingNamespace;
namespace ClassLibrary1
{


    [Export("class2", typeof(MySubInterface))]
    class Class2 : MySubInterface
    {
        public string MyProperty { get; set; }

        public Class2()
        {

            MyProperty = "Class2";
        }
    }
} 

////middle

using MyHostingNamespace;
namespace ClassLibrary1
{


    [Export("class1", typeof(MyInterface))]
    public class Class1 : MyInterface
    {
        [Import("class2", AllowDefault=true)]
        MySubInterface myClass2;

        public string MyProperty {get;set;}

        public Class1()
        {

            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            CompositionContainer _container = new CompositionContainer(catalog);
            _container.ComposeParts(this);

            MyProperty = myClass2.MyProperty;
        }
    }
}

////outer

namespace MyHostingNamespace
{
    class Program
    {
        [Import("class1")]
        public MyInterface class1;

        public Program()
        {
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryCatalog("."));
            CompositionContainer _container = new CompositionContainer(catalog);

            _container.ComposeParts(this);

        }

        static void Main(string[] args)
        {

            Program p = new Program();

            Console.WriteLine(p.class1.MyProperty);

        }

    }



    public interface MyInterface
    {
        string MyProperty { get; set; }
    }

    public interface MySubInterface
    {
        string MyProperty { get; set; }
    }
}

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