Recently, I needed to be able to instantiate a part from an [ImportMany] collection, where the collection in question was part of a factory; that is, all parts were lazily held in a central location (the factory). The clumsy way of doing this would be to get the type of a part, and use Activator to instantiate it. But a slightly more elegant (to my mind) mechanism is to use meta data to locate a part, and use the composition container to create as necessary.
Thus the extensions shown below.Given a MEF container, you can ask it to instantiate a part or parts based on a Func that will be used to select eligible parts based on the decomposed meta data held by MEF (looking at the implementation now, I'd posit that I could optimise the LINQ).
public static class MEFExtensions {
public static IEnumerable<TValue> CreateParts<TValue>(
this CompositionContainer container,
Func<IDictionary<string, object>, bool> selector) {
return container.Catalog.Parts.SelectMany(p =>
p.ExportDefinitions.Select(d =>
new Tuple<ComposablePartDefinition, ExportDefinition>(p, d))).
Where(tup => tup.Item2.ContractName == typeof(TValue).FullName &&
selector(tup.Item2.Metadata)).
Select(t => (TValue)t.Item1.CreatePart().GetExportedValue(t.Item2));
}
public static TValue CreatePart<TValue>(
this CompositionContainer container,
Func<IDictionary<string, object>, bool> selector) {
return CreateParts<TValue>(container, selector).FirstOrDefault();
}
}
As decomposed meta data in MEF is typed as an IDictionary, this next set of extensions can be used if a straight (and simple) comparison of dictionary associations is required. IOW, a selector might look similar to:
dict => dict.EqualKeysAndValues(externallySuppliedMetaData)
public static class IDictionaryExtensions {
public static bool EqualKeysAndValues<TKey, TValue>(
this IDictionary<TKey, TValue> dict, IDictionary<TKey, TValue> rhs) {
return EqualKeysAndValues(dict, rhs, Enumerable.Empty<TKey>());
}
public static bool EqualKeysAndValues<TKey, TValue>(
this IDictionary<TKey, TValue> dict
IDictionary<TKey, TValue> rhs,
IEnumerable<TKey> exclusions) {
IDictionary<TKey, TValue> comp =
new Dictionary<TKey, TValue>().AddRange(
dict.Where(kvp => !exclusions.Contains(kvp.Key)));
return comp.Count() == rhs.Count() &&
!comp.Keys.Except(rhs.Keys).Any() &&
comp.All(kvp => rhs[kvp.Key].Equals(kvp.Value));
}
public static IDictionary<TKey, TValue> AddRange<TKey, TValue>(
this IDictionary<TKey, TValue> dict,
IEnumerable<KeyValuePair<TKey, TValue>> pairs) {
pairs.ToList().ForEach(kvp => dict[kvp.Key] = kvp.Value);
return dict;
}
}
No comments:
Post a Comment