使用适当的示例在MEF中导入和导入构造函数属性之间的区别?

时间:2017-07-28 11:06:15

标签: c# .net mef

任何人都可以通过相关示例帮助我使用MEF中的Import和ImportingConstructor属性以及何时使用? [Import(AllowDefault = true)]的用途是什么?

根据我对MEF的理解:

导出属性是在类型T的类上定义的,其中T是接口,并且要创建该类的实例,应该在引用变量上定义导入属性,如下所示

[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
     // Implement the interface
}

class MyMainClass
{
   // MEF engine creates an instance as Export attribute is defined
   // on MySimpleCalculator

    [Import(typeof(ICalculator))]
    public ICalculator calculator;
}

如果在给定程序集中定义了T类型的多个导出,那么我们可以使用ImportMany属性。

那么现在有人可以解释何时在构造函数中使用Import和ImportingConstructor以及AllowDefault属性?

如果有人可以用更好的例子来解释,那就太好了。

任何帮助将不胜感激。 感谢

2 个答案:

答案 0 :(得分:1)

<强> ImportingConstructor

在示例代码中导入/导出部件的方式,如果MyMainClass正在组合,则调用隐式无参数构造函数,然后分配MySimpleCalculator的实例到calculator字段。

现在让我们假设你想要一个readonly字段/ get-only属性,或者需要访问构造函数中的ICalculator,你需要将它传递给构造函数而不是比以后分配到该领域:

public interface ICalculator
{
    bool Quack { get; }
}

[Export(typeof(ICalculator))]
public class MySimpleCalculator : ICalculator
{
    public bool Quack => true;
}

[Export]
public class MyMainClass
{
    public ICalculator Calculator { get; }
    public string Blah { get; }

    [ImportingConstructor]
    public MyMainClass(ICalculator calculator)
    {
        Calculator = calculator; // assign readonly property
        Blah = calculator.Quack ? "Foo" : "Bar"; // do something based on calculator
    }
}

现在隐式导入构造函数的参数并使用相应的导出来满足。

<强> AllowDefault

如果您[导入]某些东西,那些东西必须可用或合成失败。

如果你[导入(AllowDefault = true)]某事,组成不会&#39;如果没有相应的导出,则会失败,但是导入的值为null / false / 0。

顺便说一句:抱歉有点讽刺,但答案也可能是RTFM

答案 1 :(得分:0)

在您的应用程序中,MEF包含三个基本部分。如果继续进行笔记本电脑的类比,我们可以将这三个部分可视化为笔记本电脑上的USB端口,带有USB连接器的外部硬盘驱动器以及将USB连接器插入端口的手。用MEF术语,将端口定义为[Import]语句。该语句放在属性上方,以告诉系统此处插入了某些内容。 USB电缆定义为[Export]语句。该语句放在类,方法或属性的上方,指示这是要插入某处的项目。一个应用程序可能会(并且可能会)包含许多此类进出口。第三部分的工作是弄清楚我们拥有哪些端口,以及因此需要插入哪些电缆。这是CompositionContainer的工作。它就像手一样,插入与相应端口匹配的电缆。那些与端口不匹配的电缆将被忽略。

[ImportMany] //  It allows us to import zero or more Exported items that match. 
private IEnumerable<Lazy<IProvider, IMetaData>> _Providers;

[Export] // This tag is required if you want to create an instance in the child class
private readonly IFacade _iFacade;

#region [ MEF Loading ]

private void LoadPlugin()
{
var pluginsDirectoryPath = ConfigurationReader.PluginsDirectoryPath;
if (System.IO.Path.IsPathRooted(pluginsDirectoryPath) == false)
pluginsDirectoryPath =

System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, pluginsDirectoryPath);

pluginsDirectoryPath = System.IO.Path.GetFullPath(pluginsDirectoryPath);
if (System.IO.Directory.Exists(pluginsDirectoryPath) == false)
{
throw new CriticalException(
"The plugins directory path is not defined. Add Plugins parameter to configuration file.");
}

//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();
// Plgins only load from plugins directory for now
catalog.Catalogs.Add(new DirectoryCatalog(pluginsDirectoryPath));

//Create the CompositionContainer with the parts in the catalog
var container = new CompositionContainer(catalog);

//Fill the imports of this object
try
{
container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
throw new CriticalException("Unable to load authentication plugins", compositionException);
}
}
#endregion [ MEF Loading ]

以上所有代码都在同一个类中,现在我们需要在该类的构造函数中创建一个实例。

public ABCFacade(Ifacade iFacade)
{
LoadPlugin();
_iFacade = iFacade; // Make sure the class instance that you want to create in the child class must have a [Export] tag, like we did in above.
}


Export(typeof(IProvider))]
[ExportMetadata("ProviderName", "ABC")]
public class Plugin : IProvider
{
private readonly IFacade _iFacade;
[ImportingConstructor] // This tag will override the constructor.
public Plugin(IFacade iFacade)
{
  _iFacade = iFacade;
}
}