Language: C#
Generic catalog implementation along with acceptance test
public class GenericCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
{
private ComposablePartCatalog _decoratedCatalog;
private AggregateCatalog _catalog = new AggregateCatalog();
private IDictionary<string, Type> _closedTypes = new Dictionary<string, Type>();
private IDictionary<string, Type> _genericTypes = new Dictionary<string, Type>();
public GenericCatalog(ComposablePartCatalog catalog)
{
_decoratedCatalog = catalog;
_catalog.Catalogs.Add(_decoratedCatalog);
_catalog.Changing += (s, e) => { OnChanging(e); };
InitializeLocators();
}
private void InitializeLocators()
{
using (var ep = new CatalogExportProvider(_decoratedCatalog))
{
ep.SourceProvider = ep;
var locatorExports = ep.GetExports<TypeLocator, ITypeLocatorView>();
foreach (var export in locatorExports)
{
var locator = export.Value;
_genericTypes.Add(export.Metadata.FullName, locator.Type);
}
}
}
private void OnChanging(ComposablePartCatalogChangeEventArgs e)
{
var handler = Changing;
if (handler != null)
handler(this, e);
}
public override IQueryable<ComposablePartDefinition> Parts
{
get { return _catalog.Parts; }
}
public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
{
Type importDefinitionType = null;
var exports = _catalog.GetExports(definition);
if (!exports.Any()) {
var contractDef = definition as ContractBasedImportDefinition;
if (contractDef != null && !definition.GetType().BaseType.Equals(typeof(ImportDefinition)))
{
importDefinitionType = GetImportDefinitionType(definition);
if (ShouldCreateClosedGenericPart(contractDef, importDefinitionType))
{
CreateGenericPart(importDefinitionType);
exports = _catalog.GetExports(definition);
}
}
}
return exports;
}
private void CreateGenericPart(Type importDefinitionType)
{
var type = BuildGenericType(importDefinitionType);
var typeCatalog = new TypeCatalog(type);
_catalog.Catalogs.Add(typeCatalog);
_closedTypes.Add(importDefinitionType.FullName,type);
}
private bool ShouldCreateClosedGenericPart(ContractBasedImportDefinition contractDef, Type importDefinitionType)
{
return contractDef.Cardinality != ImportCardinality.ZeroOrMore && importDefinitionType.IsGenericType &&
!_closedTypes.ContainsKey(importDefinitionType.FullName);
}
private Type GetImportDefinitionType(ImportDefinition definition)
{
Type importDefinitionType = null;
if (ReflectionModelServices.IsImportingParameter(definition))
importDefinitionType = GetParameterType(definition);
else
importDefinitionType = GetMethodType(definition, importDefinitionType);
return importDefinitionType;
}
private Type GetMethodType(ImportDefinition definition, Type importDefinitionType)
{
var memberInfos = ReflectionModelServices.GetImportingMember(definition).GetAccessors();
var memberInfo = memberInfos[0];
if (memberInfo.MemberType == MemberTypes.Method)
{
var methodInfo = (MethodInfo) memberInfo;
importDefinitionType = methodInfo.ReturnType;
}
else if (memberInfo.MemberType == MemberTypes.Field)
{
var fieldInfo = (FieldInfo) memberInfo;
importDefinitionType = fieldInfo.FieldType;
}
return importDefinitionType;
}
private Type GetParameterType(ImportDefinition definition)
{
Type importDefinitionType;
var importingParameter = ReflectionModelServices.GetImportingParameter(definition);
var parameterInfo = importingParameter.Value;
importDefinitionType = parameterInfo.ParameterType;
return importDefinitionType;
}
private Type BuildGenericType(Type importDefinitionType)
{
var genericImportTypeDefinition = importDefinitionType.GetGenericTypeDefinition();
var genericTypeLocator = _genericTypes[genericImportTypeDefinition.FullName];
var genericType = genericTypeLocator.MakeGenericType(importDefinitionType.GetGenericArguments());
return genericType;
}
public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed;
public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing;
}
// Type locator - used for exporting generic parts
public abstract class TypeLocator
{
public TypeLocator()
{
}
public abstract Type Type { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
public class TypeLocatorAttribute : ExportAttribute
{
public TypeLocatorAttribute(Type type)
: base(typeof(TypeLocator))
{
FullName = type.FullName;
}
public string FullName { get; private set; }
}
public interface ITypeLocatorView
{
string FullName { get; }
}
// Test, illustrates importing an IRespository<Order> from an Repository<> Type locator.
[TestClass]
public class GenericCatalogFixture
{
[TestMethod]
public void When_IRepository_Customer_is_resolved_it_is_created_by_catalog()
{
var typeCatalog = new TypeCatalog(typeof(OrderProcessor), typeof(RepositoryTypeLocator),typeof(Logger));
var catalog = new GenericCatalog(typeCatalog);
var container = new CompositionContainer(catalog);
var orderProcessor = container.GetExportedValue<OrderProcessor>();
Assert.IsNotNull(orderProcessor.OrderRepository);
}
}
public class Order
{
}
[TypeLocator(typeof(IRepository<>))]
public class RepositoryTypeLocator : TypeLocator
{
public override Type Type
{
get { return typeof (Repository<>); }
}
}
[Export]
public class OrderProcessor
{
[Import]
public IRepository<Order> OrderRepository { get; set; }
}
public class Repository<T> : IRepository<T>
{
[Import]
public ILogger Logger { get; set; }
}
[InheritedExport]
public interface IRepository<T>
{
}
public class Logger : ILogger
{
}
[InheritedExport]
public interface ILogger
{
}
Tags:
Description:
GenericCatalog along with sample. Supports importing open generic types on a part. Requires implementing a derived TypeLocator for each open-generic part.
Report Abuse
Subscribe
Discuss
What's new
What is it
New Snippet
Recent Snippets
My Snippets
Web Code
Search

