如何从MEF导入创建新对象

时间:2013-02-12 11:59:10

标签: c# mef

我对MEF感到有些困惑,我以为我已经开始理解它,但看起来我并不是那么。

所以,我有一个我想读的XML测试步骤列表。想法是主应用程序在运行时对类型一无所知。

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

所以我有一个带有静态&#34;结果的基类型&#34;允许我保存信息以在步骤之间传递的类(上面的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信息,因为我确实意味着导入将为null,因此暗示我的设计思维模式是错误的。

我确实设法通过导出CompositionContainer来使其工作,然后在加载XML后我能够这样做:

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

但这对我来说感觉有点不对,因为导入的测试步骤的初始列表除了获取类型之外不能用于任何其他事情。所以我认为我应该将数据导出为MEF部分然后独立导出处理程序,然后当我从XML中读取数据列表时,我会从列表中请求处理程序?如果这有道理?

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

这更像是应该做的吗?任何帮助表示赞赏,我在发部已经相当轻松,所以我不能承受更多的损失

1 个答案:

答案 0 :(得分: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; }
    }
}