我有一个使用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的方法。如果不使用导入属性,这是否可行?
答案 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
创建政策中匹配该部分,因此我们可以匹配NonShared
和Shared
部分。
您应该可以使用此代替正常GetExportedValueOrDefault<T>
来电:
T retrievedComponent = container.GetExportedValueOrDefault<T>(CreationPolicy.NonShared);