MEF 中的 Import 和 ImportingConstructor 属性与适当示例之间的区别?

Difference between Import and ImportingConstructor attributes in MEF with proper examples?

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

根据我对 MEF 的理解:

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

[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 属性?

如果有人能用更好的例子来解释就太好了。

如有任何帮助,我们将不胜感激。 谢谢

ImportingConstructor

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

现在假设您更想拥有一个只读 field/a 只读 属性,或者需要在构造函数中访问 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
    }
}

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

允许默认

如果您 [导入] 某物,则该某物必须可用,否则组合会失败。

如果你 [Import(AllowDefault = true)] 一些东西,如果没有相应的导出,合成就不会失败,但你会得到 null/false/0 作为导入值。

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

您的应用程序中包含 MEF 的三个基本部分。如果我们用笔记本电脑做类比,我们可以将这三个部分想象成笔记本电脑上的 USB 端口、带有 USB 连接器的外部硬盘驱动器以及将 USB 连接器插入端口的手。在 MEF 术语中,端口定义为 [Import] 语句。这条语句放在 属性 之上,告诉系统这里插入了一些东西。 USB 电缆被定义为 [Export] 语句。此语句位于 class、方法或 属性 之上,以指示这是要插入某处的项目。一个应用程序可以(并且可能会)有很多这样的导出和导入。第三部分的工作是找出我们有哪些端口以及我们需要将哪些电缆插入其中。这是 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 ]

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

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;
}
}