为非Attributed Imports指定RequiredCreationPolicy

时间:2011-10-10 14:46:52

标签: c#-4.0 inversion-of-control mef

我有一个使用MEF作为DI容器的IoC包装器,下面显示了一个适用的包装器片段。

public static bool TryGetComponent<T>(out T component) 
{
    CompositionContainer container = RetrieveContainer();

    T retrievedComponent = container.GetExportedValueOrDefault<T>();
    if (retrievedComponent.Equals(default(T)))
    {
        component = default(T);
        return false;
    }

    component = retrievedComponent;

    return true;
}

CompositionContainer中的大多数导出组件指定CreationPolicy为“Any”。

[PartCreationPolicy(CreationPolicy.Any)]

对于我创建的类型,我可以轻松使用以下import属性来让MEF将导出的类型作为NonShared实例提供。

[Import(RequiredCreationPolicy = CreationPolicy.NonShared)]

但是,由于我的IoC包装器也必须由不使用MEF或其任何Import属性的类使用,并且必须使用我的IoC API来获取实例导出类型。 当我以编程方式将CompositionContainer用于GetExports和GetExportedValues 时,我需要一种指定CreationPolicy的方法。如果不使用导入属性,这是否可行?

2 个答案:

答案 0 :(得分:4)

如果您确实想要查询容器,就像使用具有RequiredCreationPolicy = NonShared的ImportAttribute一样,请尝试创建自己的自定义ContractBasedImportDefinition。构造函数的一个参数是CreationPolicy,它表示所需的创建策略。 类似的东西:

container.GetExports(new ContractBasedImportDefinition(
    AttributedModelServices.GetContractName(type),
    AttributedModelServices.GetTypeIdentity(type),
    null,
    ImportCardinality.ZeroOrMore,
    false,
    false,
    CreationPolicy.NonShared));

当然,您可以根据需要调整参数,但这会让您朝着正确的方向前进,并使容器创建标记为Any的任何部件的NonShared版本(这是默认设置)。

答案 1 :(得分:1)

好吧,CreationPolicy作为组件元数据的一部分传递。这意味着,您应该能够查询该部件的元数据,并查看它是否存在。在元数据中指定CreationPolicy的方式是使用完整类型名称System.ComponentModel.Composition.CreationPolicy作为键,并使用枚举结果作为值。所以,知道这一点我们可以建立一个扩展方法:

public static T GetExportedValueOrDefault<T>(this CompositionContainer container, CreationPolicy creationPolicy)
{
  var metadataKey = typeof(CreationPolicy).FullName;

  var lazy = container.GetExportedValueOrDefault<T, IDictionary<string, object>>();
  if (lazy == null)
    return default(T);

  if (lazy.Metadata.ContainsKey(metadataKey))
  {
    // If the creation policy matches the required, return.
    if (((CreationPolicy)lazy.Metadata[metadataKey]) == creationPolicy) 
      return lazy.Value;
  }
  else
  {
    // Return the value as we assume it satisfies the default CreationPolicy = Any
    return lazy.Value; 
  }

  return default(T);
}

现在,首先我们创建预期的密钥,然后我们获取一个Lazy<T, TMetadata>实例,其中包含类型和任何关联的元数据作为Lazy<T, IDictionary<string, object>>实例。如果懒惰以null的形式返回,我们可能会提前失败,因为根本没有匹配的部分。

接下来,我们可以检查元数据字典Lazy.Metadata以确定元数据是否存在。如果是,我们需要投射并与我们选择的元数据进行比较。如果成功,则返回我们的零件实例。

如果不成功(例如,如果部件使用CreationPolicy的隐式Any [即,导出中省略了PartCreationPolicyAttribute),我们将会假设我们可以在默认的Any创建政策中匹配该部分,因此我们可以匹配NonSharedShared部分。

您应该可以使用此代替正常GetExportedValueOrDefault<T>来电:

T retrievedComponent = container.GetExportedValueOrDefault<T>(CreationPolicy.NonShared);